package com.pcjz.lems.business.widget.lineChart;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.Rect;
import android.graphics.Shader;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import com.pcjz.lems.business.common.utils.TLog;
import com.pcjz.lems.ui.workrealname.manageequipment.CommonMethond;
import com.pcjz.lems.ui.workrealname.projectsituation.bean.LineEntity;
import java.util.ArrayList;
import java.util.List;
/**
* created by yezhengyu on 2017/9/25 17:48
*/
public class LineChartView2 extends View {
private List<LineEntity> mDatas;
/**
* 坐标轴、坐标轴字体、线条的画笔
*/
private Paint mPaint1;
private Paint mPaint2;
private Paint mPaint3;
private Paint lineOnePaint;
private Paint lineTwoPaint;
private int dateColor1 = Color.parseColor("#E8E8E8");
private int dateColor2 = Color.parseColor("#999999");
private int lineOneColor = Color.parseColor("#38AFF7");
private int lineTwoColor = Color.parseColor("#8F74FD");
private int mWidth;
private int mHeight;
private int mMaxValue;
private int mMode;
private int mSize;
private Rect mBound;
private Paint mCirclePaint;
private Paint mPaintShader;
private int[] shadeColors;
private int[] shadeColors1;
private List<Integer> mClickDistanceList = new ArrayList<>();
private Path onePath;
private Path twoPath;
private Path oneShaderPath;
private Path twoShaderPath;
private int screenWidth;
public LineChartView2(Context context) {
this(context, null);
}
public LineChartView2(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public LineChartView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void setDatas(List<LineEntity> datas, int maxValue) {
mDatas = datas;
mMaxValue = maxValue;
if (mMaxValue > 0 && mMaxValue <= 10) {
mMode = 1;
} else if (mMaxValue > 10 && mMaxValue <= 20) {
mMode = 2;
} else if (mMaxValue > 20 && mMaxValue <= 30) {
mMode = 3;
} else if (mMaxValue > 30 && mMaxValue <= 40) {
mMode = 4;
} else if (mMaxValue > 40 && mMaxValue <= 50) {
mMode = 5;
} else if (mMaxValue > 50 && mMaxValue <= 60) {
mMode = 6;
} else if (mMaxValue > 60 && mMaxValue <= 70) {
mMode = 7;
} else if (mMaxValue > 70 && mMaxValue <= 80) {
mMode = 8;
} else if (mMaxValue > 80 && mMaxValue <= 90) {
mMode = 9;
} else {
mMode = 20;
}
}
//初始化画笔
private void init() {
mPaint1 = new Paint();
mPaint1.setStrokeWidth(1);
mPaint1.setColor(dateColor1);
mPaint1.setTextSize(dp2px(11));
mPaint1.setTextAlign(Paint.Align.CENTER);
mPaint1.setAntiAlias(true);
mBound = new Rect();
mPaint2 = new Paint();
mPaint2.setStrokeWidth(2);
mPaint2.setColor(dateColor2);
mPaint2.setAntiAlias(true);
mPaint3 = new Paint();
mPaint3.setStyle(Paint.Style.STROKE);
mPaint3.setStrokeWidth(1);
mPaint3.setColor(dateColor2);
mPaint3.setAntiAlias(true);
mCirclePaint = new Paint();
mCirclePaint.setAntiAlias(true);
lineOnePaint = new Paint();
lineOnePaint.setStrokeWidth(2);
lineOnePaint.setStyle(Paint.Style.STROKE);
lineOnePaint.setTextSize(dp2px(11));
lineOnePaint.setColor(lineOneColor);
onePath = new Path();
oneShaderPath = new Path();
lineTwoPaint = new Paint();
lineTwoPaint.setStrokeWidth(2);
lineTwoPaint.setStyle(Paint.Style.STROKE);
lineTwoPaint.setTextSize(dp2px(11));
lineTwoPaint.setColor(lineTwoColor);
twoPath = new Path();
twoShaderPath = new Path();
/*shadeColors = new int[]{
Color.argb(100, 255, 86, 86), Color.argb(15, 255, 86, 86),
Color.argb(0, 255, 86, 86)};*/
shadeColors = new int[]{Color.parseColor("#38AFF7"), Color.TRANSPARENT};
shadeColors1 = new int[]{Color.parseColor("#8F74FD"), Color.TRANSPARENT};
mPaintShader = new Paint();
mPaintShader.setAntiAlias(true);
mPaintShader.setStrokeWidth(2f);
}
public void initDefaultSelect(int i) {
int size = mSize;
int x1 = mSize / 3 + size * i - size / 2;
int x2 = mSize / 3 + size * i + size / 2;
if (listener != null) {
listener.getNumber(i, (x1 + x2) / 2, mHeight);
}
mClickDistanceList.clear();
mClickDistanceList.add(i);
postInvalidate();
}
private void initView() {
DisplayMetrics dm =getResources().getDisplayMetrics();
screenWidth = dm.widthPixels;
mWidth = getWidth();
mHeight = getHeight();
mSize = screenWidth / 8;
}
int times;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
initView();
times++ ;
if (times == 1) {
if (mDatas.size() == 1) {
initDefaultSelect(0);
} else {
initDefaultSelect(1);
}
}
int value;
if (mMaxValue % mMode == 0) {
value = mMaxValue;
} else {
value = mMaxValue + mMaxValue % mMode;
}
//画坐标轴
for (int i = 0; i <= value / mMode; i++) {
canvas.drawLine(0, (mHeight * 8 / 9) - (7 * mHeight / 9) * i / (value / mMode), mWidth, (mHeight * 8 / 9) - (7 * mHeight / 9) * i / (value / mMode), mPaint1);
}
//画横坐标轴
canvas.drawLine(0, mHeight * 8 / 9, mWidth, mHeight * 8 / 9, mPaint2);
//画刻度线
for (int i = 0; i < mDatas.size(); i++) {
canvas.drawLine(mSize / 3 + mSize * i, (mHeight * 8 / 9) - 8, mSize / 3 + mSize * i, mHeight * 8 / 9, mPaint2);
}
String text = "作业数量(个)";
mPaint1.setColor(dateColor2);
mPaint1.getTextBounds(text, 0, text.length(), mBound);
//画时间
for (int i = 0; i < mDatas.size(); i++) {
canvas.drawText(mDatas.get(i).getTime(), mSize / 3 + i * mSize,
mHeight * 8 / 9 + mBound.height() * 3 / 2, mPaint1);
}
//画折线
for (int i = 0; i < mDatas.size(); i++) {
if (mDatas.size() > 1) {
if (i == 0) {
float startX = mSize / 3 + mSize * i;
float division = (float) (value - mDatas.get(i).getTowerCranes()) / value;
float startY = (division * 7 + 1) * mHeight / 9;
float startX1 = mSize / 3 + mSize * i;
float division1 = (float) (value - mDatas.get(i).getElevators()) / value;
float startY1 = ((division1 * 7 + 1)) * mHeight / 9;
onePath.moveTo(startX, startY);
oneShaderPath.moveTo(startX, startY);
twoPath.moveTo(startX1, startY1);
twoShaderPath.moveTo(startX1, startY1);
} else {
float endX = mSize / 3 + mSize * i;
float division = (float) (value - mDatas.get(i).getTowerCranes()) / value;
float endY = (division * 7 + 1) * mHeight / 9;
float endX1 = mSize / 3 + mSize * i;
float division1 = (float) (value - mDatas.get(i).getElevators()) / value;
float endY1 = (division1 * 7 + 1) * mHeight / 9;
onePath.lineTo(endX, endY);
oneShaderPath.lineTo(endX, endY);
twoPath.lineTo(endX1, endY1);
twoShaderPath.lineTo(endX1, endY1);
if (i == mDatas.size() - 1) {
oneShaderPath.lineTo(i * mSize + mSize / 3, mHeight * 8 / 9);
oneShaderPath.lineTo(mSize / 3, mHeight * 8 / 9);
oneShaderPath.close();
twoShaderPath.lineTo(i * mSize + mSize / 3, mHeight * 8 / 9);
twoShaderPath.lineTo(mSize / 3, mHeight * 8 / 9);
twoShaderPath.close();
}
}
}
}
if (mDatas.size() > 1) {
canvas.drawPath(onePath, lineOnePaint);
canvas.drawPath(twoPath, lineTwoPaint);
canvas.drawPath(oneShaderPath, getShadeColorPaint(shadeColors));
canvas.drawPath(twoShaderPath, getShadeColorPaint(shadeColors1));
}
for (int i = 0; i < mDatas.size(); i++) {
if (mClickDistanceList.contains(i)) {
float centerX = mSize / 3 + i * mSize;
float division = (float) (value - mDatas.get(i).getTowerCranes()) / value;
float centerY = (division * 7 + 1) * mHeight / 9;
float innerCircle = dp2px(5); //内圆半径
float ringWidth = dp2px(1); //圆环宽度
//绘制外圆
mCirclePaint.setColor(lineOneColor);
canvas.drawCircle(centerX, centerY, innerCircle + ringWidth, mCirclePaint);
//绘制内圆
mCirclePaint.setColor(Color.parseColor("#FFFFFF"));
canvas.drawCircle(centerX, centerY, innerCircle, mCirclePaint);
float centerX1 = mSize / 3 + i * mSize;
float division1 = (float) (value - mDatas.get(i).getElevators()) / value;
float centerY1 = (division1 * 7 + 1) * mHeight / 9;
//绘制外圆
mCirclePaint.setColor(lineTwoColor);
canvas.drawCircle(centerX1, centerY1, innerCircle + ringWidth, mCirclePaint);
//绘制内圆
mCirclePaint.setColor(Color.parseColor("#FFFFFF"));
canvas.drawCircle(centerX1, centerY1, innerCircle, mCirclePaint);
//画虚线
Path path = new Path();
path.moveTo(mSize / 3 + mSize * i, mHeight * 8 / 9);
path.lineTo(mSize / 3 + mSize * i, mHeight * 1 / 9);
PathEffect effects = new DashPathEffect(new float[]{5, 5, 5, 5}, 1);
mPaint3.setPathEffect(effects);
canvas.drawPath(path, mPaint3);
}
}
}
// 修改笔的颜色
private Paint getShadeColorPaint(int[] shadeColors) {
Shader mShader = new LinearGradient(0, 0, 0, mHeight,
shadeColors, null, Shader.TileMode.CLAMP);
// 新建一个线性渐变,前两个参数是渐变开始的点坐标,第三四个参数是渐变结束的点的坐标。连接这2个点就拉出一条渐变线了,玩过PS的都懂。然后那个数组是渐变的颜色。下一个参数是渐变颜色的分布,如果为空,每个颜色就是均匀分布的。最后是模式,这里设置的是循环渐变
mPaintShader.setShader(mShader);
return mPaintShader;
}
private int selectIndex = -1;
private getNumberListener listener;
@Override
public boolean onTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
int mChartWidthd = mSize / 3;
for (int i = 0; i < mDatas.size(); i++) {
int x1 = mChartWidthd + mSize * i - mSize / 2;
int x2 = mChartWidthd + mSize * i + mSize / 2;
int y1 = mHeight * 1 / 9;
int y2 = mHeight * 8 / 9;
if (x >= x1 && x <= x2 && y >= y1 && y <= y2) {
selectIndex = i;
//传入mData中的i,横坐标,高度
listener.getNumber(i, (x1 + x2) / 2, mHeight);
mClickDistanceList.clear();
mClickDistanceList.add(selectIndex);
invalidate();
}
}
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
public void setListener(getNumberListener listener) {
this.listener = listener;
}
public interface getNumberListener {
void getNumber(int number, int x, int y);
}
private int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="match_parent"
android:text="作业数量(个)"
android:textColor="@color/txt_gray_shallow"
android:textSize="10sp"
android:gravity="center_horizontal|bottom"/>
<TextView
android:layout_width="0dp"
android:layout_weight="7"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/ll_contain_number"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:orientation="vertical">
</RelativeLayout>
<HorizontalScrollView
android:layout_width="0dp"
android:layout_weight="7"
android:layout_height="match_parent"
android:scrollbars="none">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/rl_chart_contain"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<com.pcjz.lems.business.widget.lineChart.LineChartView2
android:id="@+id/my_line_chart"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
</RelativeLayout>
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_below="@+id/my_line_chart"
android:gravity="center_horizontal"
android:orientation="horizontal">
<View
android:layout_width="12dp"
android:layout_height="12dp"
android:background="@color/common_blue_color" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="7dp"
android:text="塔吊起重机"
android:textColor="@color/common_blue_color"
android:textSize="10sp" />
<View
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_marginLeft="20dp"
android:background="@color/common_purple_color" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="7dp"
android:text="施工升降机"
android:textColor="@color/common_purple_color"
android:textSize="10sp" />
</LinearLayout>
</LinearLayout>
package com.pcjz.lems.business.widget.lineChart;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.pcjz.lems.R;
import com.pcjz.lems.business.common.utils.TDevice;
import com.pcjz.lems.ui.workrealname.manageequipment.CommonMethond;
import com.pcjz.lems.ui.workrealname.projectsituation.bean.LineEntity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* created by yezhengyu on 2017/10/9 17:39
*/
public class LineChartLayout2 extends LinearLayout {
private Context mContext;
private List<LineEntity> mDatas;
private LineChartView2 mLineChartView;
private RelativeLayout relativeLayout;
private View chartPop;
private int maxValue;
private RelativeLayout linearLayout;
private int screenWidth;
private int screenHeight;
public LineChartLayout2(Context context) {
this(context, null);
}
public LineChartLayout2(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public LineChartLayout2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
}
public void refreshLineView(List<LineEntity> datas) {
mDatas = datas;
View view = LayoutInflater.from(mContext).inflate(R.layout.view_line_chart2, null);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
setOrientation(VERTICAL);
addView(view, lp);
relativeLayout = (RelativeLayout) view.findViewById(R.id.rl_chart_contain);
mLineChartView = (LineChartView2) view.findViewById(R.id.my_line_chart);
linearLayout = (RelativeLayout) view.findViewById(R.id.ll_contain_number);
DisplayMetrics dm =getResources().getDisplayMetrics();
screenWidth = dm.widthPixels;
screenHeight = dm.heightPixels;
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mLineChartView.getLayoutParams();
params.width = initWidth(mDatas);
mLineChartView.setLayoutParams(params);
relativeLayout.removeView(chartPop);
initMaxDatas();
initLineChartView();
postInvalidate();
initViewXml();
}
private void initViewXml() {
int intMode = CommonMethond.getInstance().getIntMode(maxValue);
int value;
if (maxValue % intMode == 0) {
value = maxValue;
} else {
value = maxValue + maxValue % intMode;
}
//获取控件的高度度要减去一个状态栏的高度
int linearLayoutHeight = screenHeight - dp2px(205) - TDevice.getStatusHeight(mContext);
for (int i = value / intMode; i >= 0; i--) {
TextView textView = new TextView(mContext);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
int top = (linearLayoutHeight * 8 / 9) - (7 * linearLayoutHeight / 9) * i / (value / intMode) - dp2px(5);
params.setMargins(0, top, dp2px(6), 0);
textView.setTextColor(getResources().getColor(R.color.txt_gray_shallow));
textView.setTextSize(10);
textView.setText(i * intMode + "");
textView.setGravity(Gravity.RIGHT);
textView.setLayoutParams(params);
linearLayout.addView(textView);
}
}
private int initWidth(List<LineEntity> datas) {
int width = screenWidth / 8 + screenWidth * datas.size() / 8 ;
if (width < screenWidth) {
return screenWidth;
} else {
return width;
}
}
private void initMaxDatas() {
//初始化datas
for (int i = 0; i < mDatas.size(); i++) {
String time = mDatas.get(i).getTime();
String subTime = time.substring(time.length() - 5, time.length());
if (subTime != null) {
mDatas.get(i).setTime(subTime);
}
}
List<Integer> list = new ArrayList<>();
for (int i = 0; i < mDatas.size(); i++) {
list.add(mDatas.get(i).getElevators());
list.add(mDatas.get(i).getTowerCranes());
}
Collections.sort(list);
maxValue = list.get(list.size() - 1).intValue();
if (maxValue <= 0) {
maxValue = 10;
}
}
private void initLineChartView() {
mLineChartView.setDatas(mDatas, maxValue);
mLineChartView.setListener(new LineChartView2.getNumberListener() {
@Override
public void getNumber(int number, int x, int y) {
relativeLayout.removeView(chartPop);
chartPop = LayoutInflater.from(mContext).inflate(R.layout.view_line_chart_pop, null);
//塔吊起重机
TextView tvTowerCrane = (TextView) chartPop.findViewById(R.id.tv_tower_crane);
//施工升降机
TextView tvElevator = (TextView) chartPop.findViewById(R.id.tv_elevator);
int selectHeights = 0;
if (mDatas != null) {
for (int i = 0; i < mDatas.size(); i++) {
int towerCranes = mDatas.get(number).getTowerCranes();
int elevators = mDatas.get(number).getElevators();
tvTowerCrane.setText(mContext.getResources().getString(R.string.number_tower_crane, towerCranes + ""));
tvElevator.setText(mContext.getResources().getString(R.string.number_elevator, elevators + ""));
if (towerCranes >= elevators) {
selectHeights = towerCranes;
} else {
selectHeights = elevators;
}
}
}
chartPop.measure(0, 0);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
if (x - chartPop.getMeasuredWidth() / 2 >= 0) {
layoutParams.leftMargin = x - chartPop.getMeasuredWidth() / 2;
} else {
layoutParams.leftMargin = 0;
}
float division = (float) (maxValue - selectHeights) / maxValue;
int topMargin = (int) ((division * 7 + 1) * y / 9 - dp2px(10) - chartPop.getMeasuredHeight());
if (topMargin >= 0) {
layoutParams.topMargin = topMargin;
} else {
layoutParams.topMargin = 0;
}
chartPop.setLayoutParams(layoutParams);
relativeLayout.addView(chartPop);
}
});
}
private int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
}
package com.pcjz.lems.ui.workrealname.projectsituation.bean;
/**
* created by yezhengyu on 2017/9/25 17:24
*/
public class LineEntity {
private String id;
private String time;
private int towerCranes;
private int elevators;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getTowerCranes() {
return towerCranes;
}
public void setTowerCranes(int towerCranes) {
this.towerCranes = towerCranes;
}
public int getElevators() {
return elevators;
}
public void setElevators(int elevators) {
this.elevators = elevators;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
画双折线和渐变色的关键代码
canvas.drawPath(onePath, lineOnePaint);
canvas.drawPath(twoPath, lineTwoPaint);
canvas.drawPath(oneShaderPath, getShadeColorPaint(shadeColors));
canvas.drawPath(twoShaderPath, getShadeColorPaint(shadeColors1));
// 修改笔的颜色
private Paint getShadeColorPaint(int[] shadeColors) {
Shader mShader = new LinearGradient(0, 0, 0, mHeight,
shadeColors, null, Shader.TileMode.CLAMP);
// 新建一个线性渐变,前两个参数是渐变开始的点坐标,第三四个参数是渐变结束的点的坐标。连接这2个点就拉出一条渐变线了,玩过PS的都懂。然后那个数组是渐变的颜色。下一个参数是渐变颜色的分布,如果为空,每个颜色就是均匀分布的。最后是模式,这里设置的是循环渐变
mPaintShader.setShader(mShader);
return mPaintShader;
}
其他画图的方法类似