Android 自定义控件--横向柱状图
来源:互联网 发布:开淘宝店页面图片 编辑:程序博客网 时间:2024/04/29 05:03
**摘要**
本文主要内容是:在Android系统下自定义图形。效果如下图:
**思路**
如上图所示,我们应该把问题简单化,看上去图片是有规律的,类似一个列表,那么我们就当一列是一个Item吧。
再把一个Item分解: 分成文字和图形部分。
文字部分
文字部分就是对当个柱状图的说明,我们暂且叫他“itemName”吧。我们看到了itemName是右对齐的,那么我们就得获取所有数据的itemName,然后看谁最长,然后计算这段文字有多长,此时,我们就知道了itemName所占的长度了(当个文字的长度 * 文字个数),获取当个文字的长宽方法如下:
/** * 获取单个字符的高和宽 */ private int[] getTextWH() { int[] wh = new int[2]; // 一个矩形 Rect rect = new Rect(); String text = "我"; Paint paint = new Paint(); // 设置文字大小 paint.setTextSize(dip2px(getContext(), 16)); paint.getTextBounds(text, 0, text.length(), rect); wh[0] = rect.width(); wh[1] = rect.height(); return wh; }
那么我们就得设置文字画笔是右对齐的。
/** *绘制文字说明 右对齐 * @param canvas * @param text */ private void drawText(Canvas canvas, String text) { int x = getWidth(); int y = getHeight(); Paint textPaint = new Paint(); textPaint.setColor(getResources().getColor(R.color.text_line_chart)); textPaint.setTextSize(dip2px(getContext(), 16)); // 设置文字右对齐 textPaint.setTextAlign(Paint.Align.RIGHT); float tX = (x - getFontlength(textPaint, text)) / 2; float tY = (y - getFontHeight(textPaint)) / 2 + getFontLeading(textPaint); // 注意第二个参数,右对齐,文字是从右开始写的,那么 x 就是对齐处的X坐标 canvas.drawText(text, mTextW, tY, textPaint); }
图形部分
图形部分主要是绘制矩形,那么怎么绘制呢?很简单的嘛: 先获取屏幕宽度SW,然后获取数值的大小DV, SW / DV 就得到了一个单位DV所占的位置了,然后直接canvas.drawRect …..但是,但是 我们是画一个列表的,要对其的,我们要的是数据有参考、对比性的。是吧???那么我们就得算出所有 DV的最大值。然后计算一个DV所占的位置,最后才能绘制。 记得,我们的图形是在 ItemName右边的。那么我们图形的X坐标就是 ItemName所占的宽度开始的。
/**绘制图形 * @param canvas */ private void drawLine(Canvas canvas) { double chart_length = (getWidth() - mTextW) / (double) mMaxV; int start_complete_left = mTextW + 10, start_complete_top = 4, start_complete_right = start_complete_left + (int) (chart_length * mData.getRecover_complete())- dip2px(getContext(), 6), start_uncomplete_right = start_complete_left + (int) (chart_length * (mData.getRecover_complete() + mData.getRecover_uncomplete()))- dip2px(getContext(), 6); Log.e("TAG", start_complete_left + "..." + start_complete_top + ",,," + start_complete_right + "ds" + start_uncomplete_right); this.arcPaint = new Paint(); this.arcPaint.setColor(getResources().getColor(R.color.line_chart_uncomplete)); this.arcPaint.setAntiAlias(true);// 去除锯齿 // 绘制未完成的, canvas.drawRect(start_complete_left, start_complete_top, start_uncomplete_right, mChartH, arcPaint); // 绘制完成的 this.arcPaint.setColor(getResources().getColor(R.color.line_chart_complete)); canvas.drawRect(start_complete_left, start_complete_top, start_complete_right, mChartH, arcPaint); }
文字加图形
画好一个,那么我们就得把 一个个item 放进列表里面去, 那么就得重写一个LinearLayout, 然后add()上去。 为什么不用ListView或者RecycleView?你一定在想,因为itemName的长度不确定,我们又得右对齐,所以只能用LinearLayout了
public LinChartLayout(Context context) { super(context); this.setOrientation(VERTICAL); setView(); } public void setView() { if (mData != null && !mData.isEmpty()) { int text_max_length = 0; int value_max = 0; for (LineChartData data : mData) { // 获取最长文字的个数 if (text_max_length <= data.getName().length()) { text_max_length = data.getName().length(); } // 获取数据值的大小 int total = data.getRecover_complete() + data.getRecover_uncomplete(); // 获取数据的值 if (value_max <= total) { value_max = total; } } int[] wh = getTextWH(); // 文字区域的宽 int textAreW = text_max_length * wh[0] + dip2px(getContext(), 10); // 图形区域的宽 int chartAreW = scrW - textAreW - 10; LinearLayout.LayoutParams layoutParams = new LayoutParams(scrW - dip2px(getContext(), 10),dip2px(getContext(), 32)); // 设置居中 layoutParams.gravity = Gravity.CENTER; // 设置Margin layoutParams.topMargin = dip2px(getContext(), 4); layoutParams.bottomMargin = dip2px(getContext(), 4); // 遍历添加LinChartView for (LineChartData i : mData) { LinChartView chartView = new LinChartView(getContext()); chartView.setData(textAreW, chartAreW,value_max, i); this.addView(chartView, layoutParams); } } }
**全部代码**
下面是一些参考的代码:
LinChartLayout.java
/** * @author bishiqiangan@yeah.net * 重写一个LinearLayout, 遍历添加LinChartView */public class LinChartLayout extends LinearLayout { /** * 列表的数据源 */ private List<LineChartData> mData; /** * 屏幕的宽 * */ private int scrW; public LinChartLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public LinChartLayout(Context context, AttributeSet attrs) { super(context, attrs); } public LinChartLayout(Context context) { super(context); this.setOrientation(VERTICAL); setView(); } public void setView() { if (mData != null && !mData.isEmpty()) { int text_max_length = 0; int value_max = 0; for (LineChartData data : mData) { // 获取最长文字的个数 if (text_max_length <= data.getName().length()) { text_max_length = data.getName().length(); } // 获取数据值的大小 int total = data.getRecover_complete() + data.getRecover_uncomplete(); // 获取数据的值 if (value_max <= total) { value_max = total; } } int[] wh = getTextWH(); // 文字区域的宽 int textAreW = text_max_length * wh[0] + dip2px(getContext(), 10); // 图形区域的宽 int chartAreW = scrW - textAreW - 10; LinearLayout.LayoutParams layoutParams = new LayoutParams(scrW - dip2px(getContext(), 10),dip2px(getContext(), 32)); // 设置居中 layoutParams.gravity = Gravity.CENTER; // 设置Margin layoutParams.topMargin = dip2px(getContext(), 4); layoutParams.bottomMargin = dip2px(getContext(), 4); // 遍历添加LinChartView for (LineChartData i : mData) { LinChartView chartView = new LinChartView(getContext()); chartView.setData(textAreW, chartAreW,value_max, i); this.addView(chartView, layoutParams); } } } /** * 获取单个字符的高和宽 */ private int[] getTextWH() { int[] wh = new int[2]; // 一个矩形 Rect rect = new Rect(); String text = "我"; Paint paint = new Paint(); // 设置文字大小 paint.setTextSize(dip2px(getContext(), 16)); paint.getTextBounds(text, 0, text.length(), rect); wh[0] = rect.width(); wh[1] = rect.height(); return wh; } public void setData(List<LineChartData> d,int scrw) { this.mData = d; this.scrW = scrw; } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 根据手机的分辨率从 px(像素) 的单位 转成为 dp */ public static int px2dip(Context context, float pxValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); }
LinChartView.java
/** * @author bishiqiangan@yeah.net * 重写一个View , 绘制一个横向柱状图 */public class LinChartView extends View { private LineChartData mData; private int mTextW, mChartH, mMaxV; private Paint arcPaint = null; public LinChartView(Context context) { super(context); } public LinChartView(Context context, AttributeSet attrs) { super(context, attrs); } public LinChartView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mData == null) { return; } // 画文字 drawText(canvas, mData.getName()); //画图形 drawLine(canvas); } /**绘制图形 * @param canvas */ private void drawLine(Canvas canvas) { double chart_length = (getWidth() - mTextW) / (double) mMaxV; int start_complete_left = mTextW + 10, start_complete_top = 4, start_complete_right = start_complete_left + (int) (chart_length * mData.getRecover_complete())- dip2px(getContext(), 6), start_uncomplete_right = start_complete_left + (int) (chart_length * (mData.getRecover_complete() + mData.getRecover_uncomplete()))- dip2px(getContext(), 6); Log.e("TAG", start_complete_left + "..." + start_complete_top + ",,," + start_complete_right + "ds" + start_uncomplete_right); this.arcPaint = new Paint(); this.arcPaint.setColor(getResources().getColor(R.color.line_chart_uncomplete)); this.arcPaint.setAntiAlias(true);// 去除锯齿 // 绘制未完成的, canvas.drawRect(start_complete_left, start_complete_top, start_uncomplete_right, mChartH, arcPaint); // 绘制完成的 this.arcPaint.setColor(getResources().getColor(R.color.line_chart_complete)); canvas.drawRect(start_complete_left, start_complete_top, start_complete_right, mChartH, arcPaint); } /** *绘制文字说明 右对齐 * @param canvas * @param text */ private void drawText(Canvas canvas, String text) { int x = getWidth(); int y = getHeight(); Paint textPaint = new Paint(); textPaint.setColor(getResources().getColor(R.color.text_line_chart)); textPaint.setTextSize(dip2px(getContext(), 16)); // 设置文字右对齐 textPaint.setTextAlign(Paint.Align.RIGHT); float tX = (x - getFontlength(textPaint, text)) / 2; float tY = (y - getFontHeight(textPaint)) / 2 + getFontLeading(textPaint); // 注意第二个参数,右对齐,文字是从右开始写的,那么 x 就是对齐处的X坐标 canvas.drawText(text, mTextW, tY, textPaint); } /** * @return 返回指定笔和指定字符串的长度 */ public static float getFontlength(Paint paint, String str) { return paint.measureText(str); } /** * @return 返回指定笔的文字高度 */ public static float getFontHeight(Paint paint) { Paint.FontMetrics fm = paint.getFontMetrics(); return fm.descent - fm.ascent; } /** * @return 返回指定笔离文字顶部的基准距离 */ public static float getFontLeading(Paint paint) { Paint.FontMetrics fm = paint.getFontMetrics(); return fm.leading - fm.ascent; } public void setData(int textW, int chartW, int max_valur, LineChartData data) { Log.e("TAG", max_valur + "...max"); this.mTextW = textW; this.mChartH = chartW; this.mMaxV = max_valur; this.mData = data; this.postInvalidate(); } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 根据手机的分辨率从 px(像素) 的单位 转成为 dp */ public static int px2dip(Context context, float pxValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); }}
LineChartData.java
/** * @author bishiqiangan@yeah.net * 数据模型类 */public class LineChartData { private int recover_complete; private String name; private int recover_uncomplete; public int getRecover_complete() { return recover_complete; } public void setRecover_complete(int recover_complete) { this.recover_complete = recover_complete; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getRecover_uncomplete() { return recover_uncomplete; } public void setRecover_uncomplete(int recover_uncomplete) { this.recover_uncomplete = recover_uncomplete; }}
调用的方法:
==android:orientation=”vertical”== 记得添加
<com.example.testandroid.LinChartLayout android:id="@+id/linechart" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="6dip" ==android:orientation="vertical"== />
Android开发技术QQ群:64026923, 欢迎你的加入
- Android 自定义控件--横向柱状图
- android自定义横向柱状图
- 自定义控件-- 柱状图--Android
- 自定义android控件,柱状图统计
- 结合Android命名空间,自定义一个横向柱状图
- Android自定义控件之动态柱状图
- android自定义带动画的柱状图控件
- android自定义控件--横向滑动的ListView
- android 自定义横向文字跑马灯控件
- 自定义控件之柱状图
- Android 自定义控件 Canvas 绘制 柱状图 ,支持触摸操作
- 自定义Android横向网格列表控件HorizontalGridView(一)
- 自定义Android横向网格列表控件HorizontalGridView(二)
- 自定义Android横向网格列表控件HorizontalGridView(三)
- 自定义Android横向网格列表控件HorizontalGridView(四)
- android自定义柱状图
- MPAndroidChart项目实战(七)——自定义横向柱状图
- 自定义控件之横向选择控件
- CentOS升级PHP(默认5.3版本,升级至5.4以上)
- 是时候弄一套开分店的标准了---抽象工厂
- Android 7.0以下去掉时间选择框中的日框
- (备忘)收拾残局: 重装后的mac
- [LeetCode]200. Number of Islands
- Android 自定义控件--横向柱状图
- 遗传算法入门到掌握(一)
- RunLoop总结:RunLoop的应用场景(五)
- 我是大神,我却行走在大神的路上
- puts() 和 scanf() 区别大吗
- git fetch的使用介绍
- 十大绝招快速提高微信公众号图文消息阅读量
- SQL学习与练习
- SAP ABAP程序优化(我也来谈谈程序优化)