package com.wise.customView;
import java.util.ArrayList;
import com.wise.data.EnergyItem;
import com.wise.extend.OnViewTouchListener;
import com.wise.wawc.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
/**
* 我的车况油耗曲线
* @author honesty
*/
public class EnergyCurveView extends View implements OnTouchListener{
private static final String TAG = "EnergyCurveView";
Context context;
//private static final float SPACING_SCALE = 40f; // 缩放间距 用于背景图过大
/**
* 距离顶部的高度
*/
private static final float SPACING_HEIGHT = 20;
/**
* y轴最高刻度 距离 y轴绘制的 间距
*/
private static final float WEIGHT = 40;
/**
* 距离左边的间距
*/
private static int SPACING = 35;
private Bitmap mTrendLine; // 点击显示的竖线
private Bitmap mMovePoint; // 曲线图移动中绘制的圆点
/**
* 实际画布宽度
*/
private float mGradientWidth;
private float mGradientHeight = 450; // 渐变条的高度
private DisplayMetrics dm; // 手机屏幕的宽高
private ArrayList<PointF> points; // 有消耗的电量时间点
private ArrayList<EnergyItem> energyItems;
private float spacingOfX; // X间距
private float spacingOfY; // Y间距,每一度的间距
private EnergyItem maxEnergy; //y坐标最大的单元
private float moveXOfFirst; // 单个按下的X坐标
OnViewTouchListener onViewTouchListener;
//长按事件Runnable
private Runnable mLongPressRunnable;
//移动的阀值,炒作这个距离算移动
private static int TOUCH_SLOP;
//是否长按
boolean isLongPress = false;
boolean isUp = false;
int fontSize;
public EnergyCurveView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
fontSize = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 14, getResources().getDisplayMetrics());
SPACING = fontSize * 2;
setOnTouchListener(this);
TOUCH_SLOP = ViewConfiguration.get(getContext()).getScaledTouchSlop();
mLongPressRunnable = new Runnable() {
@Override
public void run() {
isLongPress = true;
invalidate();
}
};
}
int index = 0;
float x = 0;
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
moveXOfFirst = event.getX(0);
x = moveXOfFirst;
isLongPress = false;
isUp = false;
postDelayed(mLongPressRunnable, ViewConfiguration.getLongPressTimeout());
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
moveXOfFirst = event.getX(0);
if(Math.abs(moveXOfFirst-x) > TOUCH_SLOP) {
//移动超过阈值,则表示移动了
removeCallbacks(mLongPressRunnable);
}
if(isLongPress){
getParent().requestDisallowInterceptTouchEvent(true);
invalidate();
}
}
if (event.getAction() == MotionEvent.ACTION_UP) {
isUp = true;
getParent().requestDisallowInterceptTouchEvent(false);
removeCallbacks(mLongPressRunnable);
moveXOfFirst = event.getX(0);
float x_Distance = 0;
boolean isLast = true;
for(int i = 0 ; i < points.size(); i++){
PointF textPoint = points.get(i);
float x = textPoint.x - moveXOfFirst;
float x_abc = Math.abs(x);
if(i == 0){
//
}else{
if(x_abc > x_Distance){
moveXOfFirst = points.get(i-1).x;
index = i - 1;
isLast = false;
break;
}
}
x_Distance = x_abc;
}
if(isLast){
if(points.size() != 0){
moveXOfFirst = points.get(points.size()-1).x;
index = points.size()-1;
}
}
//TODO 计算松手后停靠那个点
invalidate();
}
if(event.getAction() == MotionEvent.ACTION_CANCEL){
isLongPress = false;
getParent().requestDisallowInterceptTouchEvent(false);
removeCallbacks(mLongPressRunnable);
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
Paint paint = new Paint();
// 初始化绘制
initDraw(canvas, paint);
// 点击屏幕时 进行的操作, 单点,多点
if(isLongPress && (energyItems.size() > 0)){
SinglePointTouch(canvas, paint);
if(!isUp){
// 绘制 移动的 点
onPointMove(canvas, paint, moveX);
}
}
}
/**
* 初始化绘制
* @param canvas
* @param paint
*/
private void initDraw(Canvas canvas, Paint paint) {
paint.setColor(getResources().getColor(R.color.common_inactive));
paint.setAntiAlias(true);
//TODO 绘制
float dottedSpacing = mGradientHeight/5;//垂直大间隔,实线距离
float smallDotted = dottedSpacing / 5;//里面虚线距离
float value = maxEnergy.value/5;
canvas.drawLine(SPACING, SPACING_HEIGHT, SPACING, mGradientHeight + SPACING_HEIGHT, paint);//y轴
canvas.drawLine(SPACING, mGradientHeight + SPACING_HEIGHT, SPACING + mGradientWidth, mGradientHeight + SPACING_HEIGHT, paint);//x轴
float xSpacing = (mGradientWidth - fontSize)/6;
paint.setTextSize(fontSize);
for(int i = 0 ; i <= 6 ; i++){//水平刻度
String Date = (i * 5 + 1) + "" ;
canvas.drawText(Date, SPACING + i * xSpacing - fontSize/2,mGradientHeight + SPACING_HEIGHT + (int)(fontSize * 1.5),paint);
}
/* 水平线和文字 */
for (int i = 0; i <= 5; i++) {
paint.setStrokeWidth(3);
canvas.drawText(""+(int)(value * i), fontSize/2,mGradientHeight + SPACING_HEIGHT - dottedSpacing * i + fontSize/2,paint);
//canvas.drawLine(SPACING, mGradientHeight + SPACING_HEIGHT - dottedSpacing * i, mGradientWidth, mGradientHeight + SPACING_HEIGHT - dottedSpacing * i, paint);
paint.setStrokeWidth(1);
if(i != 0){
for (int j = 1; j <= 4; j++) {
//canvas.drawLine(SPACING, mGradientHeight + SPACING_HEIGHT - dottedSpacing * i + smallDotted * j,mGradientWidth, mGradientHeight + SPACING_HEIGHT - dottedSpacing * i + smallDotted * j,paint);
}
}
}
/* 绘制曲线 覆盖 剪切后的锯齿 */
for (int i = 0; i < points.size(); i++) {
paint.setStrokeWidth(3);
PointF startPoint = points.get(i);
if (i + 1 == points.size()) {// 绘制 最后一个圆点 为剪切的图片
//canvas.drawBitmap(mLastPoint,startPoint.x - mLastPoint.getWidth() / 2, startPoint.y - mLastPoint.getHeight() / 2, paint);
canvas.drawCircle(startPoint.x, startPoint.y, 3, paint);
break;
}
PointF endPoint = points.get(i + 1);
if(i%2 == 0){
//画阴影
paint.setColor(getResources().getColor(R.color.gray_light_ten));// 设置灰色
paint.setStyle(Paint.Style.FILL);//设置填满
Path path = new Path();
path.moveTo(startPoint.x, mGradientHeight + SPACING_HEIGHT);// 此点为多边形的起点
path.lineTo(startPoint.x, startPoint.y);
path.lineTo(endPoint.x, endPoint.y);
path.lineTo(endPoint.x, mGradientHeight + SPACING_HEIGHT);
path.close(); // 使这些点构成封闭的多边形
canvas.drawPath(path, paint);
}
// 绘制曲线,并且覆盖剪切后的锯齿
paint.setColor(getResources().getColor(R.color.common_blue));
canvas.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y,paint);
canvas.drawCircle(startPoint.x, startPoint.y, 3, paint);
}
}
float moveX;
/**
* 单点触控操作
* @param canvas
* @param paint
*/
private void SinglePointTouch(Canvas canvas, Paint paint) {
//顶部的度数框
if (moveXOfFirst < points.get(0).x) {
moveXOfFirst = points.get(0).x;
}
if (moveXOfFirst > points.get(points.size() - 1).x) {
moveXOfFirst = points.get(points.size() - 1).x;
}
moveX = moveXOfFirst;
// 绘制度数框 背景后的 横线
//canvas.drawBitmap(mTrendLine, SPACING, mGradientHeight + SPACING_HEIGHT - mTrendLine.getHeight() + 5, paint);
// 绘制 变动的 能耗为多少
float moveY = getMoveY(moveXOfFirst);
float energyHeight = (float) (mGradientHeight + SPACING_HEIGHT) - moveY;
String energyText = String.valueOf(energyHeight / spacingOfY);
// 为了避免误差 如果单点 手指在X轴 在预定的 X点上 那么直接将显示读书设置为 服务器传回的数据
EnergyItem energy = isInPoint(moveXOfFirst);
if (energy != null) {
energyText = String.valueOf(energy.value);
}
int indexOf = energyText.indexOf(".");
String substring = energyText.substring(0, indexOf + 2);
if(onViewTouchListener != null){
onViewTouchListener.OnViewTouch(substring,index);
}
}
/**
* 点击绘制的 黄色的 移动圆点
*/
private void onPointMove(Canvas canvas, Paint paint, float moveX) {
// 点住滑动 绘制的黄色线
if (moveX < SPACING) {
moveX = SPACING - mTrendLine.getWidth() / 2;
}
if (moveX > points.get(points.size() - 1).x) {
moveX = points.get(points.size() - 1).x - mTrendLine.getWidth() / 2;
}
canvas.drawBitmap(mTrendLine,
moveX - mTrendLine.getWidth() / 2, mGradientHeight
+ SPACING_HEIGHT - mTrendLine.getHeight() + 5,
paint);
// 绘制移动中的点
canvas.drawBitmap(mMovePoint,
moveX - mMovePoint.getWidth() / 2, getMoveY(moveX)
- mMovePoint.getWidth() / 2, paint);
}
/**
* 判断 目前手指在屏幕中X的点 是否在 结合点上
* @param moveX 手指移动中的点
* @return
*/
private EnergyItem isInPoint(float moveX) {
EnergyItem energy = null;
for (int i = 0; i < points.size(); i++) {
if (moveX == points.get(i).x) {
energy = energyItems.get(i);
break;
}
}
return energy;
}
/**
* 获取移动线条时 Y的值,
*/
private float getMoveY(float x) {
float y = mGradientHeight + SPACING_HEIGHT;
PointF first = null;
PointF second = null;
for (int i = 0; i < points.size() - 1; i++) {
PointF point_1 = points.get(i);
PointF point_2 = points.get(i + 1);
if (point_1.x <= x && point_2.x >= x) {
first = point_1;
second = point_2;
break;
}
}
// 勾股定理 :y=(y2-y1)/(x2-x1)*(x-x1)+y1
if (first != null || second != null)
y = Math.abs((second.y - first.y) / (second.x - first.x)
* (x - first.x) + first.y);
return y;
}
/**
* 初始化 加载 view 的资源图片
*/
public void setImages() {
// 背景渐变色大图
int windowW = (int) (dm.widthPixels - fontSize * 3);
mGradientWidth = windowW;
mGradientHeight = (float) (windowW*0.7);
Log.d(TAG, "dm.widthPixels = " + dm.widthPixels + ",mGradientWidth = " + mGradientWidth);
// 移动的黄色的线条
mTrendLine = BitmapFactory.decodeResource(getResources(),R.drawable.energy_trendline);
int height = mTrendLine.getHeight();
float trendLineScale = (float) mGradientHeight / height;
mTrendLine = scaleBmp(mTrendLine, 1.0f, trendLineScale); // 缩放图层
// 最后一个灰色的点
mMovePoint = BitmapFactory.decodeResource(getResources(), R.drawable.energy_trendpoint_move);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 图片缩放
* @param bitmap 需要缩放的图片
* @param scaleX X缩放比例
* @param scaleY Y缩放比例
* @return
*/
public Bitmap scaleBmp(Bitmap bitmap, float scaleX, float scaleY) {
Bitmap scaleBmp = null;
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Matrix matrix = new Matrix();
matrix.postScale(scaleX, scaleY);
scaleBmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix,false);
bitmap.recycle();
return scaleBmp;
}
public void setWindowsWH(DisplayMetrics dm) {
this.dm = dm;
setImages();
}
/**
* 通过数据 预先存入需要绘制的 连线点
* @param powers
* @param date
*/
public void initPoints(ArrayList<EnergyItem> energys) {
this.energyItems = energys;
getSpacingOfXY(energys);
points = new ArrayList<PointF>();
for (int i = 0; i < energys.size(); i++) {
float f = energys.get(i).value;
float y = ((mGradientHeight + SPACING_HEIGHT) - f * spacingOfY);
float x = (i * spacingOfX + SPACING);
PointF point = new PointF(x, y);
points.add(point);
}
}
/**
* 获取X的间距 以及 Y的间距
* @param powers
* @param date
*/
private void getSpacingOfXY(ArrayList<EnergyItem> energys) {
maxEnergy = findMaxPowers(energys);
spacingOfX = (mGradientWidth - fontSize)/ (energys.size() -1);
spacingOfY = (mGradientHeight - WEIGHT) / maxEnergy.value;
Log.d(TAG, "spacingOfY = " + spacingOfY + " , maxEnergy.value = " + maxEnergy.value);
}
/**
* 找到 数据集合中 最高能量 对应的脚标
* @param powers
* @return
*/
private static EnergyItem findMaxPowers(ArrayList<EnergyItem> energys) {
EnergyItem energy = new EnergyItem();
energy.value = 0;
for (int i = 0; i < energys.size(); i++) {
if (energys.get(i).value > energy.value) {
energy = energys.get(i);
}
}
return energy;
}
public void setOnViewTouchListener(OnViewTouchListener onViewTouchListener){
this.onViewTouchListener = onViewTouchListener;
}
public void RefreshView(){
invalidate();
}
}