项目用到的技术点
- mvp简单应用
- 自定义控件使用
1. ScrollView的自定义
因为我们需要的是折线图可以左右滑动,但是我们需要实时计算滑动距离,所以需要自己定义,代码比较简单
/*
* ScrollView并没有实现滚动监听,所以我们必须自行实现对ScrollView的监听,
* 我们很自然的想到在onTouchEvent()方法中实现对滚动横轴进行监听
*/
public class MyScrollView extends HorizontalScrollView {
private static final int SCROLL = 1;
public MyScrollView(Context context) {
super(context, null);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
}
public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* 当前滚动状态
*/
public enum ScrollType{
IDLE,TOUCH_SCROLL,FLING //IDLE 滚动停止 TOUCH_SCROLL 手指拖动滚动 FLING滚动
}
private ScrollType scrollType = ScrollType.IDLE;
private int lastScrollX;
/**
* 用于用户手指离开MyScrollView的时候获取MyScrollView滚动的Y距离,然后回调给onScroll方法中
*/
private Handler handler = new Handler(Looper.myLooper()) {
public void handleMessage(android.os.Message msg) {
if(msg.what == SCROLL) {
int scrollX = MyScrollView.this.getScrollX();
//此时的距离和记录下的距离不相等,在隔10毫秒给handler发送消息
if (lastScrollX != scrollX) { //还在滚动
lastScrollX = scrollX;
scrollType = ScrollType.FLING;
handler.sendEmptyMessageDelayed(SCROLL, 20);
} else { //停止滚动
scrollType = ScrollType.IDLE;
}
if (onScrollListener != null) {
onScrollListener.onScrollChanged(scrollType);
onScrollListener.onScroll(scrollX);
}
}
}
};
/**
* 重写onTouchEvent, 当用户的手在MyScrollView上面的时候,
* 直接将MyScrollView滑动的X方向距离回调给onScroll方法中,当用户抬起手的时候,MyScrollView可能还在滑动,所以当用户抬起手我们隔5毫秒给handler发送消息,在handler处理
* MyScrollView滑动的距离
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch(ev.getAction()){
case MotionEvent.ACTION_UP:
if(onScrollListener != null){
onScrollListener.onScroll(lastScrollX = getScrollX());
}
handler.sendEmptyMessageDelayed(SCROLL, 20);
break;
case MotionEvent.ACTION_MOVE:
scrollType = ScrollType.TOUCH_SCROLL;
if(onScrollListener != null){
onScrollListener.onScrollChanged(scrollType);
}
break;
}
return super.onTouchEvent(ev);
}
/**
* 滚动的回调接口
*/
public interface OnScrollListener{
//回调方法, 返回MyScrollView滑动的X方向距离
void onScroll(int scrollX);
//滑动监听
void onScrollChanged(ScrollType scrollType);
}
private OnScrollListener onScrollListener;
public void setOnScrollListener(OnScrollListener onScrollListener){
this.onScrollListener = onScrollListener;
}
@Override
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
return 0;
}
}
2. 折线图控件的定义
从网上弄得一个改了改 还是挺复杂的赶脚,可以一起交流交流
package zlc.com.linechartdemo.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.NinePatchDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import zlc.com.linechartdemo.MyApplication;
import zlc.com.linechartdemo.R;
import zlc.com.linechartdemo.utils.DensityUtil;
import zlc.com.linechartdemo.utils.LogUtil;
/**
* Created by zlc on 17/4/13.
*/
public class LineView extends View {
private int mViewHeight;
private boolean autoSetDataOfGird = true;
private boolean autoSetGridWidth = true;
private int dataOfAGird = 10;
private int bottomTextHeight = 0;
private ArrayList<String> bottomTextList = new ArrayList<>();
private ArrayList<Float> dataList = new ArrayList<>();
private ArrayList<Integer> xCoordinateList = new ArrayList<Integer>();
private ArrayList<Dot> drawDotList = new ArrayList<>();
private Paint bottomTextPaint = new Paint();
private Paint ycoordTextPaint = new Paint();
private int bottomTextDescent;
//popup
private Paint popupTextPaint = new Paint();
private final int bottomTriangleHeight = 12;//底三角形的高度
private boolean mShowYCoordinate = true;
private int topLineLength = DensityUtil.dp2px(getContext(), 12); //顶线长度
private int sideLineLength = DensityUtil.dp2px(getContext(),45)/3*2;// 右边间距和左边间距
public int backgroundGridWidth = DensityUtil.dp2px(getContext(),55);//背景网格宽度,也是X轴宽度
//Constants
private final int popupTopPadding = DensityUtil.dp2px(getContext(),1); //popup顶部距离
private final int popupBottomMargin = DensityUtil.dp2px(getContext(),5); // popup底部距离
private final int bottomTextTopMargin = DensityUtil.sp2px(getContext(),1);//底部文本顶边
private final int DOT_INNER_CIR_RADIUS = 4; //小点和线大小
private final int DOT_OUTER_CIR_RADIUS = DensityUtil.dp2px(getContext(),5); //点大小
private final int MIN_TOP_LINE_LENGTH = DensityUtil.dp2px(getContext(),12);//背景线密度
private final static int MIN_VERTICAL_GRID_NUM = 4;
private final static int MIN_HORIZONTAL_GRID_NUM = 1;
private final static int BOTTOM_TEXT_COLOR = Color.parseColor("#9B9A9B"); //X轴低
private final int YCOORD_TEXT_LEFT_MARGIN = 0;//DensityUtil.dip2px(getContext(), 10);
private boolean showPopup = false;
private Dot selectedDot = null;
public Canvas canvas;
OnDataListening dataListening;
int index;//当前选中的是第几个点
/**
* 曲线上总点数
*/
private Point[] mPoints;
public LineView(Context context){
this(context,null);
}
public LineView(Context context, AttributeSet attrs){
super(context, attrs);
init();
}
private void init() {
popupTextPaint.setAntiAlias(true);
popupTextPaint.setColor(Color.WHITE);
popupTextPaint.setTextSize(DensityUtil.sp2px(getContext(), 13));
popupTextPaint.setStrokeWidth(5);
popupTextPaint.setTextAlign(Paint.Align.CENTER);
bottomTextPaint.setAntiAlias(true);
bottomTextPaint.setTextSize(DensityUtil.sp2px(getContext(),12));
bottomTextPaint.setTextAlign(Paint.Align.CENTER);
bottomTextPaint.setStyle(Paint.Style.FILL);
bottomTextPaint.setColor(BOTTOM_TEXT_COLOR);
ycoordTextPaint.setAntiAlias(true);
ycoordTextPaint.setTextSize(DensityUtil.sp2px(getContext(),12));
ycoordTextPaint.setTextAlign(Paint.Align.LEFT);
ycoordTextPaint.setStyle(Paint.Style.FILL);
ycoordTextPaint.setColor(BOTTOM_TEXT_COLOR);
}
/**
* 设置滚动接口
* @param dataListening
*/
public void setDataListening(OnDataListening dataListening){
this.dataListening = dataListening;
}
private Runnable animator = new Runnable() {
@Override
public void run() {
boolean needNewFrame = false;
for(Dot dot : drawDotList){
dot.update();
if(!dot.isAtRest()){
needNewFrame = true;
}
}
if (needNewFrame) {
postDelayed(this, 0);
}
postInvalidate();
}
};
/**
* dataList will be reset when called is method.
* @param bottomTextList The String ArrayList in the bottom.
*/
public void setBottomTextList(ArrayList<String> bottomTextList){
this.dataList = null;
this.bottomTextList = bottomTextList;
Rect r = new Rect();
int longestWidth = 0;
String longestStr = "";
bottomTextDescent = 0;
for(String s : bottomTextList){
bottomTextPaint.getTextBounds(s,0,s.length(),r);
if(bottomTextHeight < r.height()){
bottomTextHeight = r.height();
}
if(autoSetGridWidth && (longestWidth<r.width())){
longestWidth = r.width();
longestStr = s;
}
if(bottomTextDescent<(Math.abs(r.bottom))){
bottomTextDescent = Math.abs(r.bottom);
}
}
if(autoSetGridWidth){
if(backgroundGridWidth<longestWidth){
backgroundGridWidth = longestWidth+(int)bottomTextPaint.measureText(longestStr,0,1);
}
if(sideLineLength<longestWidth/2){
sideLineLength = longestWidth/2;
}
}
refreshXCoordinateList(getHorizontalGridNum());
}
/**
*
* @param dataList The Integer ArrayList for showing,
* dataList.size() must < bottomTextList.size()
*/
public void setDataList(ArrayList<Float> dataList){
this.dataList = dataList;
if(dataList.size() > bottomTextList.size()){
throw new RuntimeException("dacer.LineView error:" +
" dataList.size() > bottomTextList.size() !!!");
}
if(autoSetDataOfGird){
float biggestData = 0;
for(Float i:dataList){
if(biggestData<i){
biggestData = i;
}
}
dataOfAGird = 1;
while(biggestData/10 > dataOfAGird){
dataOfAGird *= 10;
}
}
refreshAfterDataChanged();
setMinimumWidth(0); // It can help the LineView reset the Width,它可以帮助LineView重置宽度,
// I don't know the better way..我不知道更好的方法. .
postInvalidate();
}
private void refreshAfterDataChanged(){
float verticalGridNum = getVerticalGridlNum();
refreshTopLineLength(verticalGridNum);
refreshDrawDotList(verticalGridNum);
}
private float getVerticalGridlNum(){
float verticalGridNum = MIN_VERTICAL_GRID_NUM;
if(dataList != null && !dataList.isEmpty()){
for(Float integer:dataList){
if(verticalGridNum<(integer+1)){
verticalGridNum = integer+1;
}
}
}
return verticalGridNum;
}
private int getHorizontalGridNum(){
int horizontalGridNum = bottomTextList.size()-1;
return (horizontalGridNum <= MIN_HORIZONTAL_GRID_NUM) ? MIN_HORIZONTAL_GRID_NUM : horizontalGridNum;
}
private void refreshXCoordinateList(int horizontalGridNum){
xCoordinateList.clear();
for(int i=0;i<(horizontalGridNum+1);i++){
xCoordinateList.add(sideLineLength + backgroundGridWidth*i);
}
}
private void refreshDrawDotList(float verticalGridNum){
if(dataList != null && !dataList.isEmpty()){
int drawDotSize = drawDotList.size();
for(int i=0;i< dataList.size();i++){
float x = xCoordinateList.get(i);
//计算Y的值(方法1)
int t2 = DensityUtil.dp2px(MyApplication.getContext(),60);//90 180
int t88 = DensityUtil.dp2px(MyApplication.getContext(),29);//40 80
float t1 = dataList.get(i);
int y = (int)t1*t2/(int)verticalGridNum;
y = t2-y+t88;
if(dataList.size()==1){ //如果只有一个数据时居中
y = DensityUtil.dp2px(MyApplication.getContext(),50);//90 180
}
if(i > drawDotSize-1){
drawDotList.add(new Dot(x, 0, x, y, dataList.get(i)));
}else{
drawDotList.set(i, drawDotList.get(i).setTargetData(x,y,dataList.get(i)));
}
}
int temp = drawDotList.size() - dataList.size();
for(int i=0; i < temp; i++){
drawDotList.remove(drawDotList.size()-1);
}
}
removeCallbacks(animator);
post(animator);
}
private void refreshTopLineLength(float verticalGridNum){
if((mViewHeight-topLineLength-bottomTextHeight-bottomTextTopMargin)/
(verticalGridNum+2)<getPopupHeight()){
topLineLength = getPopupHeight()+DOT_OUTER_CIR_RADIUS+DOT_INNER_CIR_RADIUS+2;
}else{
topLineLength = MIN_TOP_LINE_LENGTH;
}
}
@Override
protected void onDraw(Canvas canvas) {
this.canvas = canvas;
if (mStyle == Linestyle.Curve) {
drawScrollLine(canvas);
}else{
drawLines(canvas);
}
for(Dot dot : drawDotList){
dot.select = false;
}
if(showPopup && selectedDot != null){ 画选中的点
selectedDot.select = true;
int i = (int) selectedDot.data;
float i2 = selectedDot.data-i;
// LogUtil.e("i2===",i2+"");
String value = "";
if(i2>0){
value= String.valueOf(selectedDot.data);
}else{
value = String.valueOf(i);
}
drawPopup(canvas,value, selectedDot.getPoint());
}
//画全部点
drawDots(canvas);
if(dataListening!=null){
dataListening.getData(bottomTextList.get(index),dataList.get(index),index);
}
}
/**
*
* @param canvas The canvas you need to draw on.
* @param point The Point consists of the x y coordinates from left bottom to right top.
* Like is 3
* 2
* 1
* 0 1 2 3 4 5
*/
private void drawPopup(Canvas canvas, String num, Point point){
boolean singularNum = (num.length() == 1);
int sidePadding = DensityUtil.dp2px(getContext(),singularNum? 8:5);
int x = point.x;
if(mShowYCoordinate == true)
x += YCOORD_TEXT_LEFT_MARGIN;
int y = point.y-DensityUtil.dp2px(getContext(),5);
Rect popupTextRect = new Rect();
popupTextPaint.getTextBounds(num,0,num.length(),popupTextRect);
int left= x-popupTextRect.width()/2-sidePadding;
int right = x + popupTextRect.width()/2+sidePadding;
int top;
int bottom ;
top = y - popupTextRect.height()-bottomTriangleHeight-popupTopPadding*2-popupBottomMargin;
bottom = y+popupTopPadding-popupBottomMargin;
//矩形的位置 画图片
Rect r = new Rect(left,top, right, bottom);
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.kuang);
byte chunk[] = bmp.getNinePatchChunk();
NinePatchDrawable popup = new NinePatchDrawable(bmp, chunk, new Rect(), null);
popup.setBounds(r);
popup.draw(canvas);
canvas.drawText(num, x, y-bottomTriangleHeight-popupBottomMargin, popupTextPaint);
}
private int getPopupHeight(){
Rect popupTextRect = new Rect();
popupTextPaint.getTextBounds("9",0,1,popupTextRect);
Rect r = new Rect(-popupTextRect.width()/2,
- popupTextRect.height()-bottomTriangleHeight-popupTopPadding*2-popupBottomMargin,
+ popupTextRect.width()/2,
+popupTopPadding-popupBottomMargin);
return r.height();
}
private void drawDots(Canvas canvas){
Paint bigCirPaint = new Paint();
bigCirPaint.setAntiAlias(true);
bigCirPaint.setColor(Color.parseColor("#FFFFFF"));//白点
Paint smallCirPaint = new Paint(bigCirPaint);
smallCirPaint.setColor(Color.parseColor("#85c942")); //小点
if(drawDotList!=null && !drawDotList.isEmpty()){
LogUtil.e("多少个点",drawDotList.size()+"");
for(Dot dot : drawDotList){
float x = dot.x;
if(mShowYCoordinate == true)
x += YCOORD_TEXT_LEFT_MARGIN;
int dotSize= DOT_INNER_CIR_RADIUS;
if(dot.select){
dotSize = DOT_OUTER_CIR_RADIUS;
}
canvas.drawCircle(x,dot.y,DOT_OUTER_CIR_RADIUS,bigCirPaint);
canvas.drawCircle(x,dot.y,dotSize,smallCirPaint);
}
}
}
//画折线
private void drawLines(Canvas canvas){
Paint linePaint = new Paint();
linePaint.setAntiAlias(true);
linePaint.setColor(Color.parseColor("#85c942"));
linePaint.setStrokeWidth(DOT_INNER_CIR_RADIUS);
for(int i=0; i< drawDotList.size()-1; i++){
float x1 = drawDotList.get(i).x;
float x2 = drawDotList.get(i+1).x;
if(mShowYCoordinate == true) {
x1 += YCOORD_TEXT_LEFT_MARGIN;
x2 += YCOORD_TEXT_LEFT_MARGIN;
}
canvas.drawLine(x1,
drawDotList.get(i).y,
x2,
drawDotList.get(i+1).y,
linePaint);
}
}
//画曲线
private void drawScrollLine(Canvas canvas){
mPoints = getPoints();
Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.parseColor("#85c942"));
mPaint.setStrokeWidth(DOT_INNER_CIR_RADIUS);
mPaint.setStyle(Paint.Style.STROKE);
Point startp;
Point endp;
for (int i = 0; i < mPoints.length - 1; i++)
{
startp = mPoints[i];
endp = mPoints[i + 1];
int wt = (startp.x + endp.x) / 2;
Point p3 = new Point();
p3.y = startp.y;
p3.x = wt;
Path path = new Path();
path.moveTo(startp.x, startp.y);
path.cubicTo(p3.x, p3.y, p3.x, endp.y, endp.x, endp.y); // (x1,y1) 为控制点,(x2,y2)为控制点,(x3,y3) 为结束点。
canvas.drawPath(path, mPaint);
}
}
private Point[] getPoints()
{
Point[] points = new Point[dataList.size()];
for (int i = 0; i < dataList.size(); i++) {
points[i] = new Point((int)drawDotList.get(i).x,(int)drawDotList.get(i).y);
}
return points;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int mViewWidth = measureWidth(widthMeasureSpec);
mViewHeight = measureHeight(heightMeasureSpec);
setMeasuredDimension(mViewWidth,mViewHeight);
}
private int measureWidth(int measureSpec){
int horizontalGridNum = getHorizontalGridNum();
int preferred = backgroundGridWidth * horizontalGridNum + sideLineLength*2;
return getMeasurement(measureSpec, preferred);
}
private int measureHeight(int measureSpec){
int preferred = 0;
return getMeasurement(measureSpec, preferred);
}
private int getMeasurement(int measureSpec, int preferred){
int specSize = MeasureSpec.getSize(measureSpec);
int measurement;
switch(MeasureSpec.getMode(measureSpec)){
case MeasureSpec.EXACTLY:
measurement = specSize;
break;
case MeasureSpec.AT_MOST:
measurement = Math.min(preferred, specSize);
break;
default:
measurement = preferred;
break;
}
return measurement;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//触摸时先隐藏所有的点
Point point = new Point();
point.x = (int) event.getX();
point.y = (int) event.getY();
Region r = new Region();
int width = backgroundGridWidth / 2;
if(drawDotList != null && !drawDotList.isEmpty()){
for (int i = 0; i <drawDotList.size();i++){
Dot dot = drawDotList.get(i);
r.set((int)dot.x-width,(int)dot.y- width,(int)dot.x+width,(int)dot.y+width);
if (r.contains(point.x,point.y) && event.getAction() == MotionEvent.ACTION_DOWN){
selectedDot = dot;
LogUtil.e("ACTION_DOWN","点按下");
}else if (event.getAction() == MotionEvent.ACTION_UP){
if (r.contains(point.x,point.y)){
showPopup = true;
LogUtil.e("ACTION_UP","点抬起");
index = i;
}
}
}
}
if (event.getAction() == MotionEvent.ACTION_UP){
postInvalidate();
}
return true;
}
private float updateSelf(float origin, float target, float velocity){
if (origin < target) {
origin += velocity;
} else if (origin > target){
origin-= velocity;
}
if(Math.abs(target-origin)<velocity){
origin = target;
}
return origin;
}
public class Dot{
float x;
float y;
float data;
float targetX;
float targetY;
float velocity = DensityUtil.dp2px(getContext(),20);
public boolean select = false; //有没有被选中 (自行加的)
Dot(float x,float y,float targetX,float targetY,float data){
this.x = x;
this.y = y;
setTargetData(targetX, targetY,data);
}
Point getPoint(){
return new Point((int)x,(int)y);
}
Dot setTargetData(float targetX,float targetY,float data){
this.targetX = targetX;
this.targetY = targetY;
this.data = data;
return this;
}
boolean isAtRest(){
return (x == targetX) && ( y == targetY);
}
void update(){
x = updateSelf(x, targetX, velocity);
y = updateSelf(y, targetY, velocity);
}
}
//返回每个点的距离
public int getDistance(){
return backgroundGridWidth;
}
//返回点列表
public ArrayList<Dot> getDrawDotList(){
return drawDotList;
}
//画某一个点
public void drawPopup(int index){
this.index = index;
selectedDot = drawDotList.get(index);
showPopup = true;
postInvalidate();
}
public interface OnDataListening{
void getData(String time,Float data,int index);
}
private Linestyle mStyle = Linestyle.Line;
enum Linestyle {
Line,// 折线
Curve//曲线
}
}
3. 折线图数据处理
package zlc.com.linechartdemo.mvp;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import zlc.com.linechartdemo.adapter.HealthDataAdapter;
import zlc.com.linechartdemo.utils.JsonUtil;
import zlc.com.linechartdemo.utils.LogUtil;
import zlc.com.linechartdemo.info.MetaListInfo;
import zlc.com.linechartdemo.R;
import zlc.com.linechartdemo.ui.TrendFragment;
import zlc.com.linechartdemo.info.ChartDataInfo;
import zlc.com.linechartdemo.utils.ParamsUtil;
/**
* @author : zlc
* @date : On 2017/3/22
* @eamil : zlc921022@163.com
*/
public class ChartPresentImpl implements ChartPresenter,HealthDataAdapter.OnItemClickLitener{
private FragmentActivity mActivity;
public List<ChartDataInfo.BodyBean> metaList;
public MetaListInfo datalist;
public TrendFragment fragment;
public String enName;
public String cName;
private RecyclerView id_recycle_data;
private HealthDataAdapter mDataAdapter;
private Handler handler;
public static final int DATA_REFRESH = 3; //刷新走势图数量
public static final int MOVEMENTS_REFRESH = 4; //刷新文字
public ChartPresentImpl(Handler handler,FragmentActivity activity){
this.handler = handler;
this.mActivity = activity;
metaList = new ArrayList<>();
datalist = new MetaListInfo();
datalist.nameList = new ArrayList<>();
datalist.valueList = new ArrayList<>();
datalist.unitList = new ArrayList<>();
datalist.showList = new ArrayList<>();
}
public void initView(RecyclerView id_recycle_data) {
this.id_recycle_data = id_recycle_data;
}
@Override
public void chartInfo() {
ChartDataInfo info = JsonUtil.parseJsonToBean(ParamsUtil.getChartInfo(), ChartDataInfo.class);
if(info==null){
LogUtil.e("折线图info","JSON解析失败");
}else if("1".equals(info.status) && info.body!=null && info.body.size()>0){
setChartInfo(info);
}else{
LogUtil.e("折线图info",info.msg);
}
}
@Override
public void setChartInfo(ChartDataInfo info) {
metaList.clear();
metaList.addAll(info.body);
LogUtil.e("有多少项数据",metaList.size()+"");
if(metaList!=null && metaList.size()>0){
setChartAdapter(); //给RecycleView设置Adapter
setChartFragment(info); //给折线图设置Fragment
}else{
LogUtil.e("setChartInfo","metaList没有数据");
}
}
//给RecycleView设置Adapter
private void setChartAdapter() {
datalist.clear();
for (int i = 0; i < metaList.size();i++) {
if (i == 0) {
datalist.showList.add(true);
enName = metaList.get(0).enName;
cName = metaList.get(0).name;
} else {
datalist.showList.add(false);
}
String unit = metaList.get(i).unit;
String name = metaList.get(i).name;
this.datalist.nameList.add(name);
this.datalist.unitList.add(unit);
LogUtil.e("name", name);
LogUtil.e("unit", unit);
List<ChartDataInfo.DatalistBean> datalistBeen = metaList.get(i).datalist;
String value = datalistBeen != null && datalistBeen.size() > 0 ? datalistBeen.get(0).value : "-";
this.datalist.valueList.add(value);
}
//添加尾部数据
datalist.addFootData();
id_recycle_data.setLayoutManager( new LinearLayoutManager(mActivity,LinearLayoutManager.HORIZONTAL,false));
mDataAdapter = new HealthDataAdapter(mActivity,datalist);
id_recycle_data.setAdapter(mDataAdapter);
}
//给折线图设置Fragment
private void setChartFragment(ChartDataInfo info) {
FragmentManager fm = mActivity.getSupportFragmentManager();
if(fm==null || fm.isDestroyed() || mActivity.isDestroyed()) {
LogUtil.e("setChartInfo","非法性操作异常");
return;
}
if(fragment==null){
fragment = new TrendFragment();
Bundle bundle = new Bundle();
bundle.putString("enName", enName);
bundle.putParcelableArrayList("BodyBean",info.body);
fragment.setArguments(bundle);
LogUtil.e("showFragment","折线图Fragment没有添加");
fm.beginTransaction()
.add(R.id.fl_member_data, fragment)
.show(fragment)
.commitAllowingStateLoss();
}else{
if(fragment.isHidden())
fm.beginTransaction().show(fragment).commitAllowingStateLoss();
fragment.refreshData(info.body,enName);
}
mDataAdapter.setOnItemClickLitener(this);
}
//根据时间刷新数据
public void updateAdapter(String time){
LogUtil.e("要刷新的时间",time);
if(metaList!=null&&metaList.size()>0){
datalist.valueList.clear();
for (int i=0;i<metaList.size();i++){
ChartDataInfo.BodyBean metaListBean = metaList.get(i);
List<ChartDataInfo.DatalistBean> dlist = metaListBean.datalist;
String value = "-";
if(dlist==null||dlist.size()==0){
value = "-";
}else{
for (int j = 0;j<dlist.size();j++){
ChartDataInfo.DatalistBean bean = dlist.get(j);
if(bean.date.equals(time)){
value = bean.value;
LogUtil.e("要加入的数据",bean.value);
break;
}
}
}
datalist.valueList.add(value);
}
mDataAdapter.notifyDataSetChanged();
}
}
@Override
public void onItemClick(HealthDataAdapter.ViewHolder view, int position) {
LogUtil.e("position==",position+"");
if(position >= metaList.size()){
LogUtil.e("尾部==",position+"");
return;
}
enName = metaList.get(position).enName;
cName = datalist.nameList.get(position) ;
for (int i = 0; i < metaList.size(); i++) {
if(i == position){
datalist.showList.set(i,true);
}else{
datalist.showList.set(i,false);
}
}
mDataAdapter.notifyDataSetChanged();
LogUtil.e("enName=",enName);
Message msg = handler.obtainMessage();
msg.what = MOVEMENTS_REFRESH ;
Bundle bundle= new Bundle();
bundle.putString("enName",enName);
bundle.putString("name",cName);
msg.setData(bundle);
handler.sendMessage(msg);
showFragment(enName);
}
//显示折线图Fragment
private void showFragment(String enName){
if(!fragment.isAdded()){
LogUtil.e("showFragment","折线图Fragment没有添加");
}else{
LogUtil.e("showFragment","Fragment添加过了");
fragment.refresh(enName);
}
fragment.setOnTrendDataListening(new TrendFragment.OnTrendDataListening() {
@Override
public void getData(String time, Float data) {
LogUtil.e("showFragment_time",time);
LogUtil.e("showFragment_data",data.toString());
Message msg = new Message();
msg.what = DATA_REFRESH ;
Bundle bundle= new Bundle();
bundle.putString("time",time);
bundle.putString("data",String.valueOf(data));
msg.setData(bundle);
handler.sendMessage(msg);
}
});
}
}
4. 折线图界面处理
package zlc.com.linechartdemo.ui;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.RelativeLayout;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import zlc.com.linechartdemo.R;
import zlc.com.linechartdemo.info.ChartDataInfo;
import zlc.com.linechartdemo.utils.DensityUtil;
import zlc.com.linechartdemo.utils.LogUtil;
import zlc.com.linechartdemo.utils.ScreenUtil;
import zlc.com.linechartdemo.view.LineView;
import zlc.com.linechartdemo.view.MyScrollView;
public class TrendFragment extends BaseFragment implements MyScrollView.OnScrollListener{
LineView lineView;
MyScrollView scrollView;
private Handler mHandler = new Handler(Looper.myLooper());
String enName = ""; //要刷新数据的点
int shieldingWidth = -8;//屏幕宽度
int middlePointNum = 3;
int distance = -8; //每个点的距离
int point_num = -8;//每屏有多少个点
DecimalFormat df;
ArrayList<Float> dataList = new ArrayList<>();//放数据
ArrayList<String> strList = new ArrayList<>();//放时间
private ArrayList<ChartDataInfo.BodyBean> bodyBeanList;
@Override
protected View initView() {
view = View.inflate(mActivity, R.layout.fragment_trend,null);
lineView = findView(R.id.line_view);
scrollView = findView(R.id.scrollView);
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) lineView.getLayoutParams();
int margin = ScreenUtil.getScreenWidth(mActivity) / 2 - DensityUtil.dp2px(mActivity, 30);
lp.setMargins(margin,0,margin,0);
lineView.setLayoutParams(lp);
return view;
}
@Override
protected void initData() {
bodyBeanList = getArguments().getParcelableArrayList("BodyBean");
enName = getArguments().getString("enName");
getChartData(enName);
}
@Override
protected void initListener() {
super.initListener();
df =new DecimalFormat("#.00");
distance = lineView.getDistance();
shieldingWidth = ScreenUtil.getScreenWidth(mActivity);
point_num = shieldingWidth/distance+1;
//滑动监听
scrollView.setOnScrollListener(this);
}
//获取折线图数据
private void getChartData(String enName){
this.enName = enName;
if(bodyBeanList==null || bodyBeanList.isEmpty()){
LogUtil.e("getChartData","列表没东西");
}else{
LogUtil.e("getChartData 折线图数据大小",bodyBeanList.size()+"");
for (ChartDataInfo.BodyBean bean : bodyBeanList) {
if(null !=bean && bean.enName.equals(enName)){
LogUtil.e("getChartData","找到要刷新的那项=="+enName);
setChartData(bean.datalist);
return;
}
}
}
}
//设置折线图数据
private void setChartData(List<ChartDataInfo.DatalistBean> datalist){
scrollView.setVisibility(View.INVISIBLE);
dataList.clear();
strList.clear();
if(datalist==null || datalist.size()==0 ){ //没数据
scrollView.setVisibility(View.INVISIBLE);
LogUtil.e("setChartData","chartInfo没数据");
if(onTrendDataListening!=null){
onTrendDataListening.getData("-",0f);
}
}else{
LogUtil.e("setChartData 有几条数据",datalist.size()+"");
final int width = datalist.size() == 1 ? 0 : scrollView.getChildAt(0).getMeasuredWidth();
mHandler.postDelayed((new Runnable() {
@Override
public void run() {
scrollView.scrollTo(width,0);//滑动到最后面
scrollView.setVisibility(View.VISIBLE);
}
}),200);
//
for (int i = datalist.size()-1;i >= 0; i--){
ChartDataInfo.DatalistBean datalistBean = datalist.get(i);
dataList.add(Float.valueOf(datalistBean.value));
strList.add(datalistBean.date);
}
lineView.setBottomTextList(strList);
lineView.setDataList(dataList);
lineView.drawPopup(dataList.size() - 1);//默认选中最后一个
//数据监听
lineView.setDataListening(new LineView.OnDataListening() {
@Override
public void getData(String time, Float data,final int index) {
if(onTrendDataListening!=null){
onTrendDataListening.getData(time,data);
}
LogUtil.e("setChartData 选中的是第几个==",index+"");
mHandler.postDelayed((new Runnable() {
@Override public void run() {
LogUtil.e("setChartData 前distance===",distance+"");
distance = lineView.getDistance();
int x = distance * index ;
LogUtil.e("setChartData 后distance===",distance+"");
LogUtil.e("setChartData index===",index+"");
LogUtil.e("setChartData width===",scrollView.getChildAt(0).getMeasuredWidth()+"");
scrollView.smoothScrollTo(x,0);//滑动
}
}),50);
}
});
}
}
public void refresh(String enName){
LogUtil.e("要刷新的数",enName);
if(this.enName.equals(enName)){
return;
}
getChartData(enName);
}
public void refreshData(ArrayList<ChartDataInfo.BodyBean> bodyBeanList, String enName ){
this.bodyBeanList = bodyBeanList;
this.enName = enName;
if(bodyBeanList!=null && bodyBeanList.size()>0){
LogUtil.e("refreshData","刷新数据");
getChartData(enName);
}else{
LogUtil.e("refreshData","没东西刷");
}
}
@Override
public void onScroll(int scrollX) {
int leif = DensityUtil.getScreenWidth(mActivity) / 2;
double hua = (double)(scrollX-leif) / (double) distance;
if(hua>0){
hua +=0.5;
}else{
hua -=0.5;
}
middlePointNum = (int)hua + point_num/2; //当前滑出屏的是第几个 + 一屏个数的中间数 == 当前的中间点
}
@Override
public void onScrollChanged(MyScrollView.ScrollType scrollType) {
switch (scrollType){
case IDLE:
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
//计算出当前一屏中最中间的那一个点,并显示出来
LogUtil.e("开始画点啦",middlePointNum+"");
if(middlePointNum >= lineView.getDrawDotList().size()){
middlePointNum = lineView.getDrawDotList().size()-1;
}else if(middlePointNum < 0){
middlePointNum = 0;
}
LogUtil.e("真正画点啦",middlePointNum+"");
lineView.drawPopup(middlePointNum);
}
},50);
break;
default:
break;
}
}
public interface OnTrendDataListening{
void getData(String time,Float data);
}
private OnTrendDataListening onTrendDataListening;
public void setOnTrendDataListening(OnTrendDataListening onTrendDataListening){
this.onTrendDataListening = onTrendDataListening;
}
}
5. 联系方式
qq:1509815887
email : zlc921022@163.com
phone : 18684732678
6. 下载地址