项目中最近用到各种图表,本来打算用第三方的,例如MPAndroID,这是一个十分强大的图表库,应用起来十分方便,但是最终发现和设计不太一样,没办法,只能自己写了。今天将写好的柱状图的demo贴在这,该柱状图可根据数据的功能有一下几点:
1. 根据数据的多少,动态的绘制柱状图柱子的条数;
2. 柱状图每条柱子的绘制都有动态的动画效果;
3. 每条柱子有点击事件,点击时d出提示框,显示相关信息,规定时间后,d窗自动消失。
好了,先上演示图:
下边贴出相关代码:
自定义柱状图类:
package com.example.histogram; import androID.content.Context; import androID.graphics.Canvas; import androID.graphics.color; import androID.graphics.Paint; import androID.graphics.RectF; import androID.os.Handler; import androID.text.TextPaint; import androID.util.AttributeSet; import androID.util.Log; import androID.vIEw.MotionEvent; import androID.vIEw.VIEw; import com.example.histogram.UI.UI; import java.text.NumberFormat; /** * Created by ZHANGZDon 2016/6/16 0016. * 柱状图 */ public class HistoGram extends VIEw implements Runnable { private Handler handler = new Handler(); // 用于延时更新,实现动画 private float animHeight; // 进度条动画高度 private Paint axislinePaint; // 坐标轴画笔 private Paint hlinePaint; // 内部水平虚线画笔 private Paint textPaint; // 绘制文本的画笔 private Paint recPaint; // 绘制柱状图阴影背景的画笔 private Paint dataPaint; // 绘制柱状图的画笔 private Paint textPaint2; // 绘制白色文本的画笔 private Paint textPaint3; // 绘制坐标的画笔 private Paint textPaint4; // 绘制x轴上的白色竖线的画笔 private String[] xTitleString; // x轴刻度 private String[] yTitleString; // y轴刻度 private String[] data; // 接口返回的indicatordata,用于计算柱子高度 NumberFormat numberFormat; //用于格式化数字 private float currentHeight; // 当前柱状图应有的高度,应由计算得来 private int num = -1; // 画多少条柱子,因为存在刚开机数据不足24条的情况 private float mrelativePxInHeight; private float mrelativePxInWIDth; private OnChartClickListener Listener; private int mdist; public voID setNum(int num) { this.num = num; invalIDate(); } public voID setData(String[] data) { this.data = data; invalIDate(); } public voID setxTitleString(String[] Title) { this.xTitleString = Title; invalIDate(); } public HistoGram(Context context) { this(context,null); } public HistoGram(Context context,AttributeSet attrs) { this(context,attrs,0); } public voID setTitle(String[] Title) { this.xTitleString = Title; } public HistoGram(Context context,AttributeSet attrs,int defStyleAttr) { super(context,defStyleAttr); init(context,attrs); } /** * 进行相关初始化 *** 作 * @param context * @param attrs */ private voID init(Context context,AttributeSet attrs) { axislinePaint = new Paint(); hlinePaint = new Paint(); textPaint = new Paint(); recPaint = new Paint(); dataPaint = new Paint(); textPaint2 = new Paint(); textPaint3 = new Paint(); textPaint4 = new Paint(); numberFormat = NumberFormat.getNumberInstance(); numberFormat.setMinimumFractionDigits(3); //设置打印时保留三位小数 axislinePaint.setcolor(color.parsecolor("#dbdde4")); //设置坐标轴的颜色为白色 hlinePaint.setARGB(51,255,255); textPaint.setcolor(color.parsecolor("#8593a1")); // textPaint.setTextSize(29); textPaint.setTextSize(UI.dip2px(getContext(),12)); recPaint.setcolor(color.parsecolor("#f2f5fc")); dataPaint.setcolor(color.CYAN); textPaint2.setcolor(color.WHITE); textPaint2.setTextSize(UI.dip2px(getContext(),12)); textPaint3.setcolor(color.parsecolor("#000000")); textPaint3.setTextSize(UI.dip2px(getContext(),9)); textPaint4.setcolor(color.parsecolor("#8593a1")); textPaint4.setTextSize(UI.dip2px(getContext(),6)); axislinePaint.setAntiAlias(true); hlinePaint.setAntiAlias(true); textPaint.setAntiAlias(true); recPaint.setAntiAlias(true); dataPaint.setAntiAlias(true); textPaint2.setAntiAlias(true); textPaint3.setAntiAlias(true); textPaint4.setAntiAlias(true); } @OverrIDe protected voID onDraw(Canvas canvas) { super.onDraw(canvas); if(data == null || xTitleString == null || num < 0 ) { return; } //绘制y轴刻度 Paint.FontMetrics metrics = textPaint3.getFontMetrics(); int decent = (int) metrics.descent; float wIDth = getWIDth(); float height = getHeight(); //根据原型图得出,图中每px高度在实际中的相对尺寸 mrelativePxInHeight = height / 470; //根据原型图得出,图中每px宽度在实际中的相对尺寸 mrelativePxInWIDth = wIDth / 690; textPaint3.setTextAlign(Paint.Align.RIGHT); //绘制纵坐标 yTitleString = new String[6]; yTitleString[5] = "0"; yTitleString[4] = "20"; yTitleString[3] = "40"; yTitleString[2] = "60"; yTitleString[1] = "80"; yTitleString[0] = "100"; for (int i = 0; i < yTitleString.length; i++) { canvas.drawText(yTitleString[i],88 * mrelativePxInWIDth,(72 + i * 56) * mrelativePxInHeight + decent,textPaint3); } //绘制x轴刻度 textPaint3.setTextAlign(Paint.Align.CENTER); textPaint4.setTextAlign(Paint.Align.CENTER); TextPaint textPaint = new TextPaint(); textPaint.setcolor(color.parsecolor("#000000")); textPaint.setTextSize(UI.dip2px(getContext(),9)); //计算柱子之间的间隔 //最左侧位置100 * mrelativePxInWIDth,最右侧位置630 ePxInWIDth,float totalWIDth = 630 - 100; // 柱子与之子之间的间隔 mdist = (int) (totalWIDth / (xTitleString.length + 1)); for (int i = 0; i < xTitleString.length; i++) { //绘制白色竖线 canvas.drawline((100 + (i+1) * mdist) * mrelativePxInWIDth,348 * mrelativePxInHeight,(100 + (i+1) * mdist) * mrelativePxInWIDth,352 * mrelativePxInHeight,axislinePaint); //绘制x轴文字 canvas.drawText(xTitleString[i],370 * mrelativePxInHeight,textPaint3); } // 绘制矩形阴影 for (int i = 0; i < num; i++) { RectF rectF = new RectF(); // rectF.left = 111 * relativePxInWIDth + i * 22 * relativePxInWIDth; // rectF.right = 121 * relativePxInWIDth + i * 22 * relativePxInWIDth; rectF.left = 95 * mrelativePxInWIDth + (i+1) * mdist * mrelativePxInWIDth; rectF.right = 105 * mrelativePxInWIDth +(i+1) * mdist * mrelativePxInWIDth; rectF.top = 70 * mrelativePxInHeight; rectF.bottom = 338 * mrelativePxInHeight; canvas.drawRoundRect(rectF,10,recPaint); } // 绘制x轴坐标线 for (int i = 0; i < 6; i++) { canvas.drawline(100 * mrelativePxInWIDth,(66 + i * 56) * mrelativePxInHeight + decent,630 * mrelativePxInWIDth,axislinePaint); } // 延时绘制,实现动画效果。数字越大,延时越久,动画效果就会越慢 handler.postDelayed(this,1); for (int i = 0; i < num; i++) { RectF dataRectF = new RectF(); dataRectF.left = 95 * mrelativePxInWIDth + (i + 1) * mdist * mrelativePxInWIDth; dataRectF.right = 105 * mrelativePxInWIDth + (i + 1) * mdist * mrelativePxInWIDth; dataPaint.setcolor(color.parsecolor("#3ac2d9")); //获取柱子高度 currentHeight = float.parsefloat(data[num - 1 - i]); if (currentHeight == 0) { dataRectF.top = 346 * mrelativePxInHeight; } else if (currentHeight == 100) { dataRectF.top = 70 * mrelativePxInHeight; } else { if (animHeight >= currentHeight) { dataRectF.top = 346 * mrelativePxInHeight - currentHeight / 100 * 276 * mrelativePxInHeight; } else { dataRectF.top = 346 * mrelativePxInHeight - 276 * mrelativePxInHeight * (animHeight / 100); } } dataRectF.bottom = 346 * mrelativePxInHeight; // 限制最高高度 if (dataRectF.top < 70 * mrelativePxInHeight) { dataRectF.top = 70 * mrelativePxInHeight; } canvas.drawRoundRect(dataRectF,dataPaint); } } //实现柱子增长的动画效果 @OverrIDe public voID run() { animHeight += 1; if (animHeight >= 276 * mrelativePxInHeight) { return; } else { invalIDate(); } } @OverrIDe public boolean ontouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { //获取点击坐标 float x = event.getX(); float y = event.getY(); //判断点击点的位置 float leftx = 0; float rightx = 0; for (int i = 0; i < num; i++) { leftx = 95 * mrelativePxInWIDth + (i+ 1) * mdist * mrelativePxInWIDth - mdist/2 * mrelativePxInWIDth; rightx = 105 * mrelativePxInWIDth + (i+ 1) * mdist * mrelativePxInWIDth + mdist/2 * mrelativePxInWIDth; if (x < leftx) { continue; } if (leftx <= x && x <= rightx) { //获取点击的柱子区域的y值 float top = 346 * mrelativePxInHeight - float.parsefloat(data[num - 1 - i])/ 100 * 276 * mrelativePxInHeight; float bottom = 346 * mrelativePxInHeight; if (y >= top && y <= bottom) { //判断是否设置监听 //将点击的第几条柱子,点击柱子顶部的坐值,用于d出dialog提示数据,还要返回百分比currentHeIDht = float.parsefloat(data[num - 1 - i]) if(Listener != null) { Log.e("ss","x" + x +";y:" + y); Listener.onClick(i + 1,leftx + mdist/2,top,float.parsefloat(data[num - 1 - i])); } break; } } } break; } case MotionEvent.ACTION_MOVE: Log.e("touch","ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e("touch","ACTION_UP"); break; } return true; } /** * 柱子点击时的监听接口 */ public interface OnChartClickListener { voID onClick(int num,float x,float y,float value); } /** * 设置柱子点击监听的方法 * @param Listener */ public voID setonChartClickListener(OnChartClickListener Listener) { this.Listener = Listener; } }
在xml文件中的应用:
<?xml version="1.0" enCoding="utf-8"?> <linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" xmlns:tools="http://schemas.androID.com/tools" androID:ID="@+ID/activity_main" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:orIEntation="vertical" tools:context="com.example.histogram.MainActivity"> <TextVIEw androID:layout_wIDth="match_parent" androID:layout_height="40dp" androID:gravity="center" androID:text="繁忙度指示图(%)" androID:textSize="15sp" androID:textcolor="#000000" /> <com.example.histogram.HistoGram androID:ID="@+ID/staticvIEw" androID:layout_wIDth="400dp" androID:layout_height="500dp" androID:layout_gravity="center_horizontal" androID:layout_marginBottom="14dp" androID:layout_margintop="5dp"/> </linearLayout>
在activity中的实现:
package com.example.histogram; import androID.os.Bundle; import androID.os.Handler; import androID.support.v7.app.AppCompatActivity; import androID.util.Log; import androID.vIEw.VIEw; import androID.Widget.PopupWindow; import androID.Widget.TextVIEw; public class MainActivity extends AppCompatActivity { private PopupWindow mPopupWindow; @OverrIDe protected voID onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVIEw(R.layout.activity_main); final HistoGram histoGram = (HistoGram) findVIEwByID(R.ID.staticvIEw); String[] data ={"100","20","40","80","60","30","5","5"}; final String[] Title = {"1","2","3","4","6","7","8","9","9"}; histoGram.setNum(Title.length); histoGram.setData(data); histoGram.setxTitleString(Title); histoGram.setonChartClickListener(new HistoGram.OnChartClickListener() { @OverrIDe public voID onClick(int num,float value) { //显示提示窗 VIEw inflate = VIEw.inflate(MainActivity.this,R.layout.popupwindow,null); TextVIEw textVIEw = (TextVIEw) inflate.findVIEwByID(R.ID.main_tv); textVIEw.setText(value + "%\n" + Title[num - 1]); if(mPopupWindow != null) { mPopupWindow.dismiss(); } mPopupWindow = new PopupWindow(inflate,140,60,true); mPopupWindow.settouchable(true); Log.e("ss","num" + num +";x" + x+";y"+ y + ";value" + value +";(int)((- histoGram.getHeight()) + y - 65)" +(int)((- histoGram.getHeight()) + y - 65) + "histoGram.getHeight()" + histoGram.getHeight()); // 设置好参数之后再show // Toast.makeText(MainActivity.this,"num" + num +";x" + x+";y"+ y + ";value" + value // +";popupWindow.getWIDth()"+ mPopupWindow.getWIDth()+";"+ mPopupWindow.getHeight(),Toast.LENGTH_SHORT).show(); mPopupWindow.showAsDropDown(histoGram,(int)(x - 65),(int)((- histoGram.getHeight()) + y - 65) ); mPopupWindow.setBackgroundDrawable(getResources().getDrawable(R.mipmap.databg_busyness)); new Handler().postDelayed(new Runnable(){ public voID run() { mPopupWindow.dismiss(); } },1000); } }); } }
以上所述是小编给大家介绍的AndroID自定义带增长动画和点击d窗提示效果的柱状图,实现一个模拟后台数据登入的效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对编程小技巧网站的支持!
总结以上是内存溢出为你收集整理的Android自定义带增长动画和点击d窗提示效果的柱状图DEMO全部内容,希望文章能够帮你解决Android自定义带增长动画和点击d窗提示效果的柱状图DEMO所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)