Android 上自定义的复式折线图(三)
2016-06-30 18:21
471 查看
Android 上自定义的复式折线图(一)
Android 上自定义的复式折线图(二)
有兴趣的话可以看下前面两篇文章,这几天也对其做了很多处理,尽量将其做的更加完美这次修改也主要是为了然Y轴不动,表格可以进行水平滚动
其中做了以下支持:
设置左边控件的宽度
设置两个控件父控件的宽度
X,Y字体跟表格的距离
设置XY轴的颜色
X,Y字体颜色跟大小
表格颜色
是否显示表格
是否显示虚线
设置XY轴的文字标签
设置数据组
设置数据颜色组
效果图如下:注意第一张是表格来的,做图有问题
图一主要的实现原理:
把其弄成两个控件即左右两个,右边的用HorizontalScrollView包着,这样就可以实现水平滚动了,然后在弄个LinerLayout包着左右两个控件就OK了
首先定义一个LineViewUtil把其两个控件绑定在一起
一丶定义LineViewUtil工具类
import android.app.Activity; import android.widget.HorizontalScrollView; import android.widget.LinearLayout; import java.util.ArrayList; /** * Created by shaolin on 6/30/16. */ public class LineViewUtil { private static LineViewUtil mInstances; private Activity mContext; private LinearLayout mLayout; //父元素 private LeftView mLeftView; private RightView mRightView; private HorizontalScrollView mScroll; public static synchronized LineViewUtil getInstance() { if (mInstances == null) { mInstances = new LineViewUtil(); } return mInstances; } public LineViewUtil() { } public LinearLayout getView() { return mLayout; } public void setView(Activity context) { mContext = context; mScroll = new HorizontalScrollView(mContext); mScroll.setHorizontalScrollBarEnabled(false); mLayout = new LinearLayout(mContext); mLeftView = new LeftView(mContext); mRightView = new RightView(mContext); mScroll.addView(mRightView); mLayout.addView(mLeftView); mLayout.addView(mScroll); } //设置左边控件的宽度 public void setLeftViewWidth(int leftViewWidth) { mLeftView.setWidth(leftViewWidth); mRightView.setLeftViewWidth(leftViewWidth); } //设置两个控件父控件的宽度 public void setWidth(int partentWidth) { mLeftView.setPartentWidth(partentWidth); mRightView.setPartentWidth(partentWidth); } //X轴字体跟表格的距离 public void setXTextToLine(int textToLine) { mRightView.setTextToLine(textToLine); } //Y轴字体跟表格的距离 public void setYTextToLine(int textToLine) { mLeftView.setTextToLine(textToLine); } //设置XY轴的颜色 public void setXYColor(int XYColor) { mLeftView.setXYColor(XYColor); mRightView.setXYColor(XYColor); } public void setXTextColor(int XTextColor) { mRightView.setXTextColor(XTextColor); } public void setYTextColor(int YTextColor) { mLeftView.setYTextColor(YTextColor); } //如果是多条数据图这里是数据的默认颜色,即没有设置数据颜色组时会起作用 public void setDefDataColor(int dataColor) { mRightView.setDefDataColor(dataColor); } public void setXTextSize(int XTextSize) { mRightView.setXTextSize(XTextSize); } public void setYTextSize(int YTextSize) { mLeftView.setYTextSize(YTextSize); } public void setGridColor(int gridColor) { mRightView.setGridColor(gridColor); } //是否虚线 public void setShowDashed(boolean isDottedLine) { mRightView.setShowDashed(isDottedLine); } public void setShowGrid(boolean isShowGrid) { mLeftView.setShowGrid(isShowGrid); mRightView.setShowGrid(isShowGrid); } //设置XY轴的文字标签 public void setXYLabel(ArrayList<String> xlabel, ArrayList<String> ylabel) { mLeftView.setYLabel(ylabel); mRightView.setXYLabel(xlabel, ylabel); } //设置数据组 public void setDataList(ArrayList<ArrayList<Integer>> dataLists) { mRightView.setDataList(dataLists); } //设置数据颜色组 public void setDataColorList(ArrayList<Integer> dataColorList) { mRightView.setDataColorList(dataColorList); } }二丶左边的Y轴标签控件LeftView
import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.View; import java.util.ArrayList; /** * Created by shaolin on 6/28/16. */ public class LeftView extends View { private static final String TAG = "LeftView"; private int Xscale; private int Yscale; private int Xpoint; private int Ypoint; // Y轴上面的显示文字 private ArrayList<String> YLabel; private int YTextSize = 8; private int YTextColor = Color.WHITE; private int defXCount = 10; private int width = 40; private int height; private int partentWidth; private int textToLine; private int XYColor = Color.WHITE; //是否显示表格 private boolean isGrid = false; public LeftView(Context context) { this(context, null); } public LeftView(Context context, AttributeSet attrs) { super(context, attrs); initSize(); } private void initSize() { YLabel = new ArrayList<>(); setYTextSize(YTextSize); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Xscale = (partentWidth - width * 2) / defXCount; Yscale = Xscale / 2; height = Yscale * YLabel.size() + Yscale; Xpoint = width; Ypoint = Yscale * YLabel.size(); Log.e(TAG, "width:" + width + " ;height:" + height); setMeasuredDimension(width, height); } @Override protected void onDraw(Canvas canvas) { Paint p1 = new Paint(); p1.setStyle(Paint.Style.STROKE); p1.setAntiAlias(true); p1.setColor(XYColor); p1.setStrokeWidth(2); drawYText(canvas); if (!isGrid) { drawYLine(canvas, p1); } } private void drawYText(Canvas canvas) { Paint p = new Paint(); p.setAntiAlias(true); p.setColor(YTextColor); p.setTextSize(YTextSize); p.setTextAlign(Paint.Align.RIGHT); // 纵轴数据 for (int i = 0; i < YLabel.size(); i++) { int startY = Ypoint - i * Yscale; canvas.drawText(this.YLabel.get(i), width - 10 - textToLine, startY + Yscale / 4, p); } } //画纵轴 private void drawYLine(Canvas canvas, Paint p) { p.setColor(XYColor); float stopX = Xpoint; float stopY = Ypoint - Yscale * (YLabel.size() - 1); canvas.drawLine(Xpoint, Ypoint, stopX, stopY, p); // Y轴最后是否有箭头 canvas.drawLine(stopX, stopY, stopX - Xscale / 6, stopY + Yscale / 3, p); // canvas.drawLine(stopX, stopY, stopX + Xscale / 6, stopY + Yscale / 3, p); } public void setWidth(int width) { this.width = width; } public void setTextToLine(int textToLine) { this.textToLine = textToLine; } public void setYLabel(ArrayList<String> YLabel) { this.YLabel = YLabel; } public void setPartentWidth(int partentWidth) { this.partentWidth = partentWidth; } public void setYTextSize(int YTextSize) { this.YTextSize = setDimensionSP(YTextSize); } public void setYTextColor(int YTextColor) { this.YTextColor = YTextColor; } public void setXYColor(int XYColor) { this.XYColor = XYColor; } public void setShowGrid(boolean isGrid) { this.isGrid = isGrid; } public int setDimensionDIP(int size) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, Resources.getSystem().getDisplayMetrics()); } public int setDimensionSP(int size) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, size, Resources.getSystem().getDisplayMetrics()); } }三丶Y轴右边的表格等数据RightView控件
import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.DashPathEffect; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathEffect; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.View; import java.util.ArrayList; /** * Created by shaolin on 6/28/16. */ public class RightView extends View { private static final String TAG = "RightView"; // 原点坐标 private int Xpoint; private int Ypoint; // X,Y轴的单位长度,即表格中的正方形的宽高 private int Yscale; private int Xscale; //是否显示表格 private boolean isGrid = false; //是否展示表格为虚线 private boolean isDashed = false; // X最左边跟Y左下面的线的颜色 private int XYColor = Color.WHITE; // X轴字体的颜色 private int XTextColor = Color.WHITE; // 表格字体的颜色 private int GridColor = Color.WHITE; // 数据字体的颜色 private int defDataColor = Color.WHITE; private int XTextSize = 8; // X轴上面的显示文字 private ArrayList<String> XLabel; // Y轴上面的显示文字 private ArrayList<String> YLabel; // 曲线数据 private ArrayList<ArrayList<Integer>> dataLists; private ArrayList<Integer> dataColorList; // 单前数据 private ArrayList<Integer> dataList; private int color; private int defXCount = 10; private int dataCount; private int width; private int height; private int partentWidth; private int leftViewWidth = 40; private int textToLine; public RightView(Context context) { this(context, null); } public RightView(Context context, AttributeSet attrs) { super(context, attrs); initSize(); } private void initSize() { XLabel = new ArrayList<>(); YLabel = new ArrayList<>(); dataColorList = new ArrayList<>(); dataList = new ArrayList<>(); dataLists = new ArrayList<>(); setXTextSize(XTextSize); } protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (dataLists.size() > 0 && partentWidth > 0) { Xscale = (partentWidth - leftViewWidth * 2) / defXCount; Yscale = Xscale / 2; if (dataLists.get(0).size() <= defXCount) { dataCount = defXCount; } else { dataCount = dataLists.get(0).size(); } } width = Xscale * dataCount + leftViewWidth; height = Yscale * YLabel.size() + Yscale + XTextSize; Xpoint = 0; Ypoint = Yscale * YLabel.size(); Log.e(TAG, "width:" + width + " ;height:" + height); setMeasuredDimension(width, height); } @Override protected void onDraw(Canvas canvas) { Paint p1 = new Paint(); p1.setStyle(Paint.Style.STROKE); p1.setAntiAlias(true); p1.setColor(XYColor); p1.setStrokeWidth(2); if (isGrid) { this.drawTable(canvas); } else { this.drawXLine(canvas, p1); this.drawYLine(canvas, p1); } if (dataLists != null) { for (int i = 0; i < dataLists.size(); i++) { this.drawData(canvas, i); } } } // 画表格 private void drawTable(Canvas canvas) { Paint paint = new Paint(); paint.setStyle(Paint.Style.STROKE); paint.setColor(GridColor); Path path = new Path(); if (isDashed) { PathEffect effects = new DashPathEffect(new float[]{5, 5, 5, 5}, 1);//画虚线 paint.setPathEffect(effects); } int startX = 0; int startY = 0; int stopX = 0; int stopY = 0; // 纵向线 for (int i = 0; i <= dataCount; i++) { startX = Xpoint + i * Xscale; startY = Ypoint; stopY = Ypoint - (this.YLabel.size() - 1) * Yscale; if (i != 0) { path.moveTo(startX - Xscale / 2, startY); path.lineTo(startX - Xscale / 2, stopY); canvas.drawPath(path, paint); } path.moveTo(startX, startY); path.lineTo(startX, stopY); canvas.drawPath(path, paint); } // 横向线 for (int i = 0; i < YLabel.size(); i++) { startX = Xpoint; startY = Ypoint - i * Yscale; stopX = Xpoint + (dataCount) * Xscale; path.moveTo(startX, startY); path.lineTo(stopX, startY); paint.setColor(GridColor); canvas.drawPath(path, paint); } } //画纵轴 private void drawYLine(Canvas canvas, Paint p) { p.setColor(XYColor); float stopX = Xpoint; float stopY = Ypoint - Yscale * (YLabel.size() - 1); canvas.drawLine(Xpoint, Ypoint, stopX, stopY, p); // Y轴最后是否有箭头 // canvas.drawLine(stopX, stopY, stopX - Xscale / 6, stopY + Yscale / 3, p); canvas.drawLine(stopX, stopY, stopX + Xscale / 6, stopY + Yscale / 3, p); } // 画横轴 private void drawXLine(Canvas canvas, Paint p) { p.setColor(XYColor); float stopX = Xpoint + Xscale * dataCount; float stopY = Ypoint; canvas.drawLine(Xpoint, Ypoint, stopX, stopY, p); // X轴最后是否有箭头 canvas.drawLine(stopX, stopY, stopX - Xscale / 6, stopY - Yscale / 3, p); canvas.drawLine(stopX, stopY, stopX - Xscale / 6, stopY + Yscale / 3, p); } // 画数据 private void drawData(Canvas canvas, int pos) { dataList = dataLists.get(pos); if (dataColorList.size() == 0) { color = defDataColor; } else { color = dataColorList.get(pos); } Paint p = new Paint(); p.setAntiAlias(true); /* // 纵轴数据 for (int i = 0; i < YLabel.size(); i++) { int startY = Ypoint - i * Yscale; p.setColor(YTextColor); p.setTextSize(XTextSize); p.setTextAlign(Paint.Align.RIGHT); canvas.drawText(this.YLabel.get(i), this.Margin / 4 * 3 + marginLeft, startY + this.Margin / 4, p); }*/ //横轴数据 for (int i = 0; i < dataCount; i++) { int startX = Xpoint + i * Xscale; p.setColor(XTextColor); p.setTextSize(XTextSize); p.setTextAlign(Paint.Align.CENTER); String text = ""; if (i < XLabel.size()) { text = this.XLabel.get(i); } canvas.drawText(text, startX + Xscale / 2, Ypoint + XTextSize + 5 + textToLine, p); p.setColor(dataColorList.size() > 0 ? color : defDataColor); if (i < XLabel.size()) { canvas.drawCircle(startX + Xscale / 2, calY(dataList.get(i)), 4, p); } if (i < XLabel.size() - 1) { canvas.drawLine(startX + Xscale / 2, calY(dataList.get(i)), Xpoint + (i + 1) * Xscale + Xscale / 2, calY(dataList.get(i + 1)), p); } } } private int calY(int y) { int y0 = 0; int y1 = 0; try { y0 = Integer.parseInt(YLabel.get(0)); y1 = Integer.parseInt(YLabel.get(1)); } catch (Exception e) { return 0; } try { return Ypoint - ((y - y0) * Yscale / (y1 - y0)); } catch (Exception e) { return 0; } } public void setLeftViewWidth(int leftViewWidth) { this.leftViewWidth = leftViewWidth; } public void setPartentWidth(int partentWidth) { this.partentWidth = partentWidth; } public void setTextToLine(int textToLine) { this.textToLine = textToLine; } public void setXYColor(int XYColor) { this.XYColor = XYColor; } public void setXTextColor(int XTextColor) { this.XTextColor = XTextColor; } public void setGridColor(int gridColor) { this.GridColor = gridColor; } public void setDefDataColor(int defDataColor) { this.defDataColor = defDataColor; } public void setXTextSize(int XTextSize) { this.XTextSize = setDimensionSP(XTextSize); } public void setShowDashed(boolean isDashed) { this.isDashed = isDashed; } public void setShowGrid(boolean isGrid) { this.isGrid = isGrid; } public void setXYLabel(ArrayList<String> xlabel, ArrayList<String> ylabel) { this.XLabel = xlabel; this.YLabel = ylabel; } public void setDataList(ArrayList<ArrayList<Integer>> dataLists) { this.dataLists = dataLists; postInvalidate(); } public void setDataColorList(ArrayList<Integer> dataColorList) { this.dataColorList = dataColorList; } public int setDimensionDIP(int size) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, Resources.getSystem().getDisplayMetrics()); } public int setDimensionSP(int size) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, size, Resources.getSystem().getDisplayMetrics()); } }四丶这里在弄个例子出来是不是就比较完美了,这就来...
MainActivity.java
public class MainActivity extends Activity { private ArrayList<Integer> colorList = new ArrayList<>(); private ArrayList<String> XLabel = new ArrayList<>(); private ArrayList<String> YLabel = new ArrayList<>(); private LineViewUtil mUtil; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); mUtil = LineViewUtil.getInstance(); mUtil.setView(this); mUtil.setXYLabel(XLabel, YLabel); mUtil.setDataColorList(colorList); mUtil.setWidth(getLineViewWidth()); mUtil.setShowGrid(true); mUtil.setGridColor(Color.LTGRAY); randSet(mUtil); LinearLayout layout = (LinearLayout) findViewById(R.id.layout); layout.addView(mUtil.getView()); } private void initData() { colorList.add(getResources().getColor(R.color.using_before)); colorList.add(getResources().getColor(R.color.using_after)); for (int i = 0; i < 15; i++) { XLabel.add(String.valueOf(i + 1)); } for (int i = 0; i < 11; i++) { YLabel.add(String.valueOf(i * 10)); } } private void randSet(LineViewUtil util) { ArrayList<ArrayList<Integer>> dataLists = new ArrayList<>(); ArrayList<Integer> dataList1 = new ArrayList<Integer>(); int random1 = (int) (Math.random() * 99 + 1); for (int i = 0; i < XLabel.size(); i++) { dataList1.add((int) (Math.random() * random1)); } ArrayList<Integer> dataList2 = new ArrayList<Integer>(); int random2 = (int) (Math.random() * 99 + 1); for (int i = 0; i < XLabel.size(); i++) { dataList2.add((int) (Math.random() * random2)); } dataLists.add(dataList1); dataLists.add(dataList2); util.setDataList(dataLists); } private int getLineViewWidth() { return getWindowManager().getDefaultDisplay().getWidth(); } }activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#55000000" android:orientation="vertical"> <LinearLayout android:id="@+id/layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" /> </LinearLayout>colors.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="using_before">#f6e749</color> <color name="using_after">#7ae6fe</color> </resources>
Demo:http://download.csdn.net/detail/qq_30552993/9564198
相关文章推荐
- 使用Socket处理跨进程的实时聊天
- Android开发之RecyclerView的使用全解
- 如何高效的学习Android动画
- android studio log打不全,主要是json太多
- Android中ListView分页加载数据
- Android Marshmallow实现文字选中
- 获取Android进程中的包名
- AndroidStudio--Error converting bytecode to dex
- 使用AIDL实现Android的跨进程通信
- android的TextView中显示url
- android焦点
- /AndroidRuntime(11765): android.view.InflateException: Binary XML file line #19: Error inflating cla
- Android Volley完全解析(四),带你从源码的角度理解Volley
- Android中View的事件体系(3)——自定义横向滚动viewGroup
- 利用 LeakCanary 来检查 Android 内存泄漏
- android 使用Canvas画箭头
- RxBus使用
- Android MVP模式的详情以及和MVC模式的区别
- Android 应用监听后台切换前台的方法
- android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事项