用户登录
用户注册

分享至

简单介绍android实现可以滑动的平滑曲线图

  • 作者: 老实人妙勇
  • 来源: 51数据库
  • 2022-09-20
导读 这篇文章主要为大家详细介绍了android实现可以滑动的平滑曲线图,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了android实现可以滑动的平滑曲线图的具体代码,供大家参考,具体内容如下

直接上代码,里面有详细注解

1 attr 属性编写

 
< attr="" name="xy_line_color" format="color">
    < !--="" xy坐标轴宽度="" --="">
    < attr="" name="xy_line_width" format="dimension">
    < !--="" xy坐标轴文字颜色="" --="">
    < attr="" name="xy_text_color" format="color">
    < !--="" xy坐标轴文字大小="" --="">
    < attr="" name="xy_text_size" format="dimension">
    < !--="" 折线图中折线的颜色="" --="">
    < attr="" name="line_color" format="color">
    
    < attr="" name="interval" format="dimension">
    < !--="" 背景颜色="" --="">
    < attr="" name="bg_color" format="color">
    < !--="" 曲线选中外部颜色="" --="">
    < attr="" name="select_circle_color" format="color">
    < !--="" 曲线选中内部颜色="" --="">
    < attr="" name="select_reminder_color" format="color">
    < !--是否抬手滚动--="">
    < attr="" name="isScroll" format="boolean">
    < declare-styleable="" name="ChartView">
        < attr="" name="xy_line_color">
        < attr="" name="xy_line_width">
        < attr="" name="xy_text_color">
        < attr="" name="xy_text_size">
        < attr="" name="line_color">
        < attr="" name="interval">
        < attr="" name="bg_color">
        < attr="" name="select_circle_color">
        < attr="" name="select_reminder_color">
        < attr="" name="isScroll">
        < !--提示框跟滑动显示的位置--="">
        < attr="" name="show_position">
            < enum="" name="first" value="1">
            < enum="" name="middle" value="2">
            < enum="" name="end" value="3">
        < ttr="">
< eclare-styleable="">

2 ChartView

package com.laisontech.commonuilibrary.customviews;
 
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
 
import com.laisontech.commonuilibrary.R;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/**
 * 自定义折线图
 */
public class ChartView extends View {
    private static final int FIRST = 1;
    private static final int MIDDLE = 2;
    private static final int END = 3;
    //xy坐标轴颜色
    private int xyLineColor = 0xffCFE2CF;
    //折线选中的圆形颜色
    private int selectCircleColor = 0xff00A8FF;
    //选中数据提示框颜色
    private int selectReminderColor = 0xff00A8FF;
    //折线中圆形内部部颜色
    private int xyTextColor = 0xff0014FF;
    //折线图中折线的颜色
    private int lineColor = 0xffFD00FF;
    //xy坐标轴宽度
    private int xyLineWidth = dpToPx(1);
    //xy坐标轴文字大小
    private int xyTextSize = spToPx(12);
    //x轴各个坐标点水平间距
    private int interval = dpToPx(40);
    //背景颜色
    private int bgColor = 0xffffffff;
    //是否有起手时的滑动感
    private boolean isScroll = false;
    //提示框显示位置
    private int mShowPositionType = 3;
    //绘制XY轴坐标对应的画笔
    private Paint mXYPaint;
    //绘制XY轴的文本对应的画笔
    private Paint mXYTextPaint;
    //画折线对应的画笔
    private Paint mSpinnerLinePaint;
    private int width;
    private int height;
    //x轴的原点坐标
    private int mXOri;
    //y轴的原点坐标
    private int mYOri;
    //第一个点X的坐标
    private float mXInit;
    //第一个点对应的最大X坐标
    private float maxXInit;
    //第一个点对应的最小X坐标
    private float minXInit;
    //x轴坐标对应的数据
    private List mXData = new ArrayList<>();
    //y轴坐标对应的数据
    private List mYData = new ArrayList<>();
    //折线对应的数据
    private Map mSpinnerValue = new HashMap<>();
    //点击的点对应的X轴的第几个点,默认1
    private int selectIndex = 1;
    //X轴刻度文本对应的最大矩形,为了选中时,在x轴文本画的框框大小一致,获取从数据中得到的x轴数据,获得最长数据
    private Rect xValueRect;
    //速度检测器
    private VelocityTracker mTracker;
    //是否为短距离滑动
    private boolean isShortSlide = false;
    //获取尺寸的的中间
    private int mSelectMiddle = 0;
    //曲线切率
    private float mLineSmoothness = 0.18f;
 
    public ChartView(Context context) {
        this(context, null);
    }
 
    public ChartView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
 
    public ChartView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
        initPaint();
    }
 
    //设置切率
    public void setLineSmoothness(float lineSmoothness) {
        if (lineSmoothness != this.mLineSmoothness) {
            this.mLineSmoothness = lineSmoothness;
        }
    }
 
    /**
     * 初始化
     */
    private void initPaint() {
        mXYPaint = new Paint();
        mXYPaint.setAntiAlias(true);
        mXYPaint.setStrokeWidth(xyLineWidth);
        mXYPaint.setStrokeJoin(Paint.Join.ROUND);
        mXYPaint.setColor(xyLineColor);
 
        mXYTextPaint = new Paint();
        mXYTextPaint.setAntiAlias(true);
        mXYTextPaint.setTextSize(xyTextSize);
        mXYTextPaint.setStrokeJoin(Paint.Join.ROUND);
        mXYTextPaint.setColor(xyTextColor);
        mXYTextPaint.setStyle(Paint.Style.STROKE);
 
        mSpinnerLinePaint = new Paint();
        mSpinnerLinePaint.setAntiAlias(true);
        mSpinnerLinePaint.setStrokeWidth(xyLineWidth);
        mSpinnerLinePaint.setColor(lineColor);
        mSpinnerLinePaint.setStyle(Paint.Style.STROKE);
        mSpinnerLinePaint.setStrokeJoin(Paint.Join.ROUND);
    }
 
    /**
     * 初始化
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ChartView, defStyleAttr, 0);
        int count = array.getIndexCount();
        for (int i = 0; i < count;="" i++)="" {="" int="" attr="array.getIndex(i);" if="" (attr="=" r.styleable.chartview_xy_line_color)="" {="" xylinecolor="array.getColor(attr," xylinecolor);="" }="" else="" if="" (attr="=" r.styleable.chartview_xy_line_width)="" {="" xylinewidth="(int)" array.getdimension(attr,="" typedvalue.applydimension(typedvalue.complex_unit_px,="" xylinewidth,="" getresources().getdisplaymetrics()));="" }="" else="" if="" (attr="=" r.styleable.chartview_xy_text_color)="" {="" xytextcolor="array.getColor(attr," xytextcolor);="" }="" else="" if="" (attr="=" r.styleable.chartview_xy_text_size)="" {="" xytextsize="(int)" array.getdimension(attr,="" typedvalue.applydimension(typedvalue.complex_unit_px,="" xytextsize,="" getresources().getdisplaymetrics()));="" }="" else="" if="" (attr="=" r.styleable.chartview_line_color)="" {="" linecolor="array.getColor(attr," linecolor);="" }="" else="" if="" (attr="=" r.styleable.chartview_interval)="" {="" interval="(int)" array.getdimension(attr,="" typedvalue.applydimension(typedvalue.complex_unit_px,="" interval,="" getresources().getdisplaymetrics()));="" }="" else="" if="" (attr="=" r.styleable.chartview_bg_color)="" {="" bgcolor="array.getColor(attr," bgcolor);="" }="" else="" if="" (attr="=" r.styleable.chartview_select_circle_color)="" {="" selectcirclecolor="array.getColor(attr," selectcirclecolor);="" }="" else="" if="" (attr="=" r.styleable.chartview_select_reminder_color)="" {="" selectremindercolor="array.getColor(attr," selectremindercolor);="" }="" else="" if="" (attr="=" r.styleable.chartview_isscroll)="" {="" isscroll="array.getBoolean(attr," isscroll);="" }="" else="" if="" (attr="=" r.styleable.chartview_show_position)="" {="" mshowpositiontype="array.getInt(attr," mshowpositiontype);="" }="" }="" array.recycle();="" }="" @override="" protected="" void="" onlayout(boolean="" changed,="" int="" left,="" int="" top,="" int="" right,="" int="" bottom)="" {="" if="" (changed)="" {="" width="getWidth();" height="getHeight();" y轴文本的最大宽度="" float="" textywdith="getTextBounds(mYData.get(getListItemMaxIndex(mYData))" +="" "",="" mxytextpaint).width();="" for="" (int="" i="0;" i="">< mydata.size();="" i++)="" {//求取y轴文本最大的宽度="" float="" temp="getTextBounds(mYData.get(i)" +="" "",="" mxytextpaint).width();="" if="" (temp=""> textYWdith)
                    textYWdith = temp;
            }
            int dp2 = dpToPx(2);
            int dp3 = dpToPx(3);
            mXOri = (int) (dp2 + textYWdith + dp2 + xyLineWidth);
            //获取x轴的最长文本的宽度所占的矩形
            xValueRect = getTextBounds(mXData.get(getListItemMaxIndex(mXData)), mXYTextPaint);
            //X轴文本高度
            float textXHeight = xValueRect.height();
            for (int i = 0; i < mxdata.size();="" i++)="" {="" rect="" rect="getTextBounds(mXData.get(i)" +="" "",="" mxytextpaint);="" if="" (rect.height()=""> textXHeight)
                    textXHeight = rect.height();
                if (rect.width() > xValueRect.width())
                    xValueRect = rect;
            }
            mYOri = (int) (height - dp2 - textXHeight - dp3 - xyLineWidth);
            mXInit = mXOri + xValueRect.width() / 2 + dpToPx(5);
            minXInit = width - (width - mXOri) * 0.1f - interval * (mXData.size() - 1);
            maxXInit = mXInit;
        }
        selectIndex = getSelectIndexFromShowType(mShowPositionType);
        super.onLayout(changed, left, top, right, bottom);
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(bgColor);
        drawXY(canvas);
        drawBrokenLineAndPoint(canvas);
    }
 
    /**
     * 绘制交点处对应的点
     */
    private void drawBrokenLineAndPoint(Canvas canvas) {
        if (mXData.size() <= 0)="" return;="" int="" layerid="canvas.saveLayer(0," 0,="" width,="" height,="" null,="" canvas.all_save_flag);="" drawbrokenline(canvas);="" drawbrokenpoint(canvas);="" 将超出x轴坐标的部分截掉="" mspinnerlinepaint.setstyle(paint.style.fill);="" mspinnerlinepaint.setcolor(bgcolor);="" mspinnerlinepaint.setxfermode(new="" porterduffxfermode(porterduff.mode.clear));="" rectf="" rectf="new" rectf(0,="" 0,="" mxori,="" height);="" canvas.drawrect(rectf,="" mspinnerlinepaint);="" mspinnerlinepaint.setxfermode(null);="" canvas.restoretocount(layerid);="" }="" *="" *="" 绘制曲线对应的点="" */="" private="" void="" drawbrokenpoint(canvas="" canvas)="" {="" float="" dp2="dpToPx(2);" float="" dp4="dpToPx(4);" float="" dp7="dpToPx(7);" log.e("selectindex",="" "index:"="" +="" selectindex);="" 绘制节点="" for="" (int="" i="0;" i="">< mxdata.size();="" i++)="" {="" float="" x="mXInit" +="" interval="" *="" i;="" float="" y="mYOri" -="" myori="" *="" (1="" -="" 0.1f)="" *="" mspinnervalue.get(mxdata.get(i))="" mydata.get(mydata.size()="" -="" 1);="" 绘制选中点="" if="" (i="=" selectindex="" -="" 1)="" {="" mspinnerlinepaint.setstyle(paint.style.fill);="" 设置选中颜色="" mspinnerlinepaint.setcolor(selectcirclecolor);="" canvas.drawcircle(x,="" y,="" dp7,="" mspinnerlinepaint);="" mspinnerlinepaint.setcolor(selectremindercolor);="" canvas.drawcircle(x,="" y,="" dp4,="" mspinnerlinepaint);="" drawfloattextbox(canvas,="" x,="" y="" -="" dp7,="" mspinnervalue.get(mxdata.get(i)));="" }="" 绘制普通节点="" mspinnerlinepaint.setstyle(paint.style.fill);="" mspinnerlinepaint.setcolor(color.white);="" canvas.drawcircle(x,="" y,="" dp2,="" mspinnerlinepaint);="" mspinnerlinepaint.setstyle(paint.style.stroke);="" mspinnerlinepaint.setcolor(linecolor);="" canvas.drawcircle(x,="" y,="" dp2,="" mspinnerlinepaint);="" }="" }="" *="" *="" 绘制浮动框="" *="" */="" private="" void="" drawfloattextbox(canvas="" canvas,="" float="" x,="" float="" y,="" int="" text)="" {="" int="" dp6="dpToPx(6);" int="" dp18="dpToPx(18);" p1="" path="" path="new" path();="" path.moveto(x,="" y);="" p2="" path.lineto(x="" -="" dp6,="" y="" -="" dp6);="" p3="" path.lineto(x="" -="" dp18,="" y="" -="" dp6);="" p4="" path.lineto(x="" -="" dp18,="" y="" -="" dp6="" -="" dp18);="" p5="" path.lineto(x="" +="" dp18,="" y="" -="" dp6="" -="" dp18);="" p6="" path.lineto(x="" +="" dp18,="" y="" -="" dp6);="" p7="" path.lineto(x="" +="" dp6,="" y="" -="" dp6);="" p1="" path.lineto(x,="" y);="" canvas.drawpath(path,="" mspinnerlinepaint);="" mspinnerlinepaint.setcolor(color.white);="" mspinnerlinepaint.settextsize(sptopx(14));="" rect="" rect="getTextBounds(text" +="" "",="" mspinnerlinepaint);="" canvas.drawtext(text="" +="" "",="" x="" -="" rect.width()="" 2,="" y="" -="" dp6="" -="" (dp18="" -="" rect.height())="" 2,="" mspinnerlinepaint);="" }="" *="" *="" 绘制平滑曲线="" */="" private="" void="" drawbrokenline(canvas="" canvas)="" {="" mspinnerlinepaint.setstyle(paint.style.stroke);="" mspinnerlinepaint.setcolor(linecolor);="" 绘制折线="" path="" path="new" path();="" float="" prepreviouspointx="Float.NaN;" float="" prepreviouspointy="Float.NaN;" float="" previouspointx="Float.NaN;" float="" previouspointy="Float.NaN;" float="" currentpointx="Float.NaN;" float="" currentpointy="Float.NaN;" float="" nextpointx;="" float="" nextpointy;="" int="" linesize="mXData.size();" for="" (int="" i="0;" i="">< linesize;="" i++)="" {="" float="" x;="" float="" y;="" if="" (float.isnan(currentpointx))="" {="" currentpointx="getSpinnerPoint(i).x;" currentpointy="getSpinnerPoint(i).y;" }="" if="" (float.isnan(previouspointx))="" {="" 是第一个点?="" if="" (i=""> 0) {
                    previousPointX = getSpinnerPoint(i - 1).x;
                    previousPointY = getSpinnerPoint(i - 1).y;
                } else {
                    //用当前点表示上一个点
                    previousPointX = currentPointX;
                    previousPointY = currentPointY;
                }
            }
 
            if (Float.isNaN(prePreviousPointX)) {
                //是前两个点?
                if (i > 1) {
                    prePreviousPointX = getSpinnerPoint(i - 2).x;
                    prePreviousPointY = getSpinnerPoint(i - 2).y;
                } else {
                    //当前点表示上上个点
                    prePreviousPointX = previousPointX;
                    prePreviousPointY = previousPointY;
                }
            }
 
            // 判断是不是最后一个点了
            if (i < linesize="" -="" 1)="" {="" nextpointx="getSpinnerPoint(i" +="" 1).x;="" nextpointy="getSpinnerPoint(i" +="" 1).y;="" }="" else="" {="" 用当前点表示下一个点="" nextpointx="currentPointX;" nextpointy="currentPointY;" }="" if="" (i="=" 0)="" {="" 将path移动到开始点="" path.moveto(currentpointx,="" currentpointy);="" }="" else="" {="" 求出控制点坐标="" final="" float="" firstdiffx="(currentPointX" -="" prepreviouspointx);="" final="" float="" firstdiffy="(currentPointY" -="" prepreviouspointy);="" final="" float="" seconddiffx="(nextPointX" -="" previouspointx);="" final="" float="" seconddiffy="(nextPointY" -="" previouspointy);="" final="" float="" firstcontrolpointx="previousPointX" +="" (mlinesmoothness="" *="" firstdiffx);="" final="" float="" firstcontrolpointy="previousPointY" +="" (mlinesmoothness="" *="" firstdiffy);="" final="" float="" secondcontrolpointx="currentPointX" -="" (mlinesmoothness="" *="" seconddiffx);="" final="" float="" secondcontrolpointy="currentPointY" -="" (mlinesmoothness="" *="" seconddiffy);="" 画出曲线="" path.cubicto(firstcontrolpointx,="" firstcontrolpointy,="" secondcontrolpointx,="" secondcontrolpointy,="" currentpointx,="" currentpointy);="" }="" 更新="" prepreviouspointx="previousPointX;" prepreviouspointy="previousPointY;" previouspointx="currentPointX;" previouspointy="currentPointY;" currentpointx="nextPointX;" currentpointy="nextPointY;" }="" canvas.drawpath(path,="" mspinnerlinepaint);="" }="" *="" *="" 绘制xy坐标="" */="" private="" void="" drawxy(canvas="" canvas)="" {="" int="" length="dpToPx(5);//刻度的长度" 绘制y坐标="" canvas.drawline(mxori="" -="" xylinewidth="" 2,="" 0,="" mxori="" -="" xylinewidth="" 2,="" myori,="" mxypaint);="" 绘制箭头="" mxypaint.setstyle(paint.style.stroke);="" path="" path="new" path();="" path.moveto(mxori="" -="" xylinewidth="" 2="" -="" dptopx(5),="" dptopx(12));="" path.lineto(mxori="" -="" xylinewidth="" 2,="" xylinewidth="" 2);="" path.lineto(mxori="" -="" xylinewidth="" 2="" +="" dptopx(5),="" dptopx(12));="" canvas.drawpath(path,="" mxypaint);="" 绘制刻度="" int="" ylength="(int)" (myori="" *="" (1="" -="" 0.1f)="" (mydata.size()="" -="" 1));//y轴上面空出10%,计算出y轴刻度间距="" for="" (int="" i="0;" i="">< mydata.size();="" i++)="" {="" 绘制刻度="" canvas.drawline(mxori,="" myori="" -="" ylength="" *="" i="" +="" xylinewidth="" 2,="" mxori="" +="" length,="" myori="" -="" ylength="" *="" i="" +="" xylinewidth="" 2,="" mxypaint);="" mxytextpaint.setcolor(xytextcolor);="" 绘制文本="" string="" text="mYData.get(i)" +="" "";="" rect="" rect="getTextBounds(text," mxytextpaint);="" canvas.drawtext(text,="" 0,="" text.length(),="" mxori="" -="" xylinewidth="" -="" dptopx(2)="" -="" rect.width(),="" myori="" -="" ylength="" *="" i="" +="" rect.height()="" 2,="" mxytextpaint);="" }="" 绘制坐标="" canvas.drawline(mxori,="" myori="" +="" xylinewidth="" 2,="" width,="" myori="" +="" xylinewidth="" 2,="" mxypaint);="" 绘制箭头="" mxypaint.setstyle(paint.style.stroke);="" path="new" path();="" 整个长度="" float="" xlength="mXInit" +="" interval="" *="" (mxdata.size()="" -="" 1)="" +="" (width="" -="" mxori)="" *="" 0.1f;="" if="" (xlength="">< width)="" xlength="width;" path.moveto(xlength="" -="" dptopx(12),="" myori="" +="" xylinewidth="" 2="" -="" dptopx(5));="" path.lineto(xlength="" -="" xylinewidth="" 2,="" myori="" +="" xylinewidth="" 2);="" path.lineto(xlength="" -="" dptopx(12),="" myori="" +="" xylinewidth="" 2="" +="" dptopx(5));="" canvas.drawpath(path,="" mxypaint);="" 绘制x轴刻度="" for="" (int="" i="0;" i="">< mxdata.size();="" i++)="" {="" float="" x="mXInit" +="" interval="" *="" i;="" if="" (x="">= mXOri) {//只绘制从原点开始的区域
                mXYTextPaint.setColor(xyTextColor);
                canvas.drawLine(x, mYOri, x, mYOri - length, mXYPaint);
                //绘制X轴文本
                String text = mXData.get(i);
                Rect rect = getTextBounds(text, mXYTextPaint);
                if (i == selectIndex - 1) {
                    mXYTextPaint.setColor(lineColor);
                    canvas.drawText(text, 0, text.length(), x - rect.width() / 2, mYOri + xyLineWidth + dpToPx(2) + rect.height(), mXYTextPaint);
                    canvas.drawRoundRect(x - xValueRect.width() / 2 - dpToPx(3), mYOri + xyLineWidth + dpToPx(1), x + xValueRect.width() / 2 + dpToPx(3), mYOri + xyLineWidth + dpToPx(2) + xValueRect.height() + dpToPx(2), dpToPx(2), dpToPx(2), mXYTextPaint);
                } else {
                    canvas.drawText(text, 0, text.length(), x - rect.width() / 2, mYOri + xyLineWidth + dpToPx(2) + rect.height(), mXYTextPaint);
                }
            }
        }
    }
 
    private float startX;
    private float startx;
 
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isScrolling)
            return super.onTouchEvent(event);
            //当该view获得点击事件,就请求父控件不拦截事件
        this.getParent().requestDisallowInterceptTouchEvent(true);
        obtainVelocityTracker(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = event.getX();
                startx = event.getX();
                Log.e("XXXX", "down:" + startX + "");
                break;
            case MotionEvent.ACTION_MOVE:
                //滑动距离小于等于8的时候任务为短距离滑动
                //当前x轴的尺寸与设置的x轴间隔的距离之乘积大于 屏幕中的显示布局宽度与x轴七点之差时,开始移动
                if (interval * mXData.size() > width - mXOri) {
                    //获取滑动的距离
                    float dis = event.getX() - startX;
                    //重新赋值给startX
                    startX = event.getX();
                    //当前x原点距离与左右滑动的距离之和没有最小值大,则将当前x距离赋值为最小,以下相似
                    if (mXInit + dis < minxinit)="" {="" mxinit="minXInit;" }="" else="" if="" (mxinit="" +="" dis=""> maxXInit) {
                        mXInit = maxXInit;
                    } else {
                        mXInit = mXInit + dis;
                    }
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
                isShortSlide = Math.abs(event.getX() - startx) <= dptopx(8);="" clickaction(event);="" scrollafteractionup();="" this.getparent().requestdisallowintercepttouchevent(false);="" recyclevelocitytracker();="" break;="" case="" motionevent.action_cancel:="" 增加这行代码防止与父类的滑动事件冲突="" this.getparent().requestdisallowintercepttouchevent(false);="" recyclevelocitytracker();="" break;="" }="" return="" true;="" }="" 是否正在滑动="" private="" boolean="" isscrolling="false;" *="" *="" 手指抬起后的滑动处理="" */="" private="" void="" scrollafteractionup()="" {="" if="" (!isscroll)="" return;="" final="" float="" velocity="getVelocity();" float="" scrolllength="maxXInit" -="" minxinit;="" if="" (math.abs(velocity)="">< 10000)="" scrolllength="(maxXInit" -="" minxinit)="" *="" math.abs(velocity)="" 10000;="" valueanimator="" animator="ValueAnimator.ofFloat(0," scrolllength);="" animator.setduration((long)="" (scrolllength="" (maxxinit="" -="" minxinit)="" *="" 1000));//时间最大为1000毫秒,此处使用比例进行换算="" animator.setinterpolator(new="" decelerateinterpolator());="" animator.addupdatelistener(new="" valueanimator.animatorupdatelistener()="" {="" @override="" public="" void="" onanimationupdate(valueanimator="" valueanimator)="" {="" float="" value="(float)" valueanimator.getanimatedvalue();="" if="" (velocity="">< 0="" &&="" mxinit=""> minXInit) {//向左滑动
                    if (mXInit - value <= minxinit)="" mxinit="minXInit;" else="" mxinit="mXInit" -="" value;="" }="" else="" if="" (velocity=""> 0 && mXInit < maxxinit)="" {//向右滑动="" if="" (mxinit="" +="" value="">= maxXInit)
                        mXInit = maxXInit;
                    else
                        mXInit = mXInit + value;
                }
                invalidate();
            }
        });
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                isScrolling = true;
            }
 
            @Override
            public void onAnimationEnd(Animator animator) {
                isScrolling = false;
            }
 
            @Override
            public void onAnimationCancel(Animator animator) {
                isScrolling = false;
            }
 
            @Override
            public void onAnimationRepeat(Animator animator) {
 
            }
        });
        animator.start();
 
    }
 
    /**
     * 获取速度
     *
     * @return
     */
    private float getVelocity() {
        if (mTracker != null) {
            mTracker.computeCurrentVelocity(1000);
            return mTracker.getXVelocity();
        }
        return 0;
    }
 
    /**
     * 点击X轴坐标或者折线节点
     *  */
    // 44  142  139
    private void clickAction(MotionEvent event) {
        int dp8 = dpToPx(8);
        float eventX = event.getX();
        float eventY = event.getY();
        if (!isShortSlide) {
            for (int i = 0; i < mxdata.size();="" i++)="" {="" float="" x="mXInit" +="" interval="" *="" i;="" float="" start="mXOri;" if="" (x="">= start + (mSelectMiddle - 1) * interval && x < start="" +="" mselectmiddle="" *="" interval)="" {="" selectindex="i" +="" 1;="" invalidate();="" }="" }="" return;="" }="" for="" (int="" i="0;" i="">< mxdata.size();="" i++)="" {="" 节点="" float="" x="mXInit" +="" interval="" *="" i;="" float="" y="mYOri" -="" myori="" *="" (1="" -="" 0.1f)="" *="" mspinnervalue.get(mxdata.get(i))="" mydata.get(mydata.size()="" -="" 1);="" if="" (eventx="">= x - dp8 && eventX <= x="" +="" dp8="" &&="" eventy="">= y - dp8 && eventY <= y="" +="" dp8="" &&="" selectindex="" !="i" +="" 1)="" {//每个节点周围范围内都是可点击区域="" selectindex="i" +="" 1;="" invalidate();="" return;="" }="" x轴刻度="" string="" text="mXData.get(i);" rect="" rect="getTextBounds(text," mxytextpaint);="" x="mXInit" +="" interval="" *="" i;="" y="mYOri" +="" xylinewidth="" +="" dptopx(2);="" if="" (eventx="">= x - rect.width() / 2 - dp8 && eventX <= x="" +="" rect.width()="" +="" dp8="" 2="" &&="" eventy="">= y - dp8 && eventY <= y="" +="" rect.height()="" +="" dp8="" &&="" selectindex="" !="i" +="" 1)="" {="" selectindex="i" +="" 1;="" invalidate();="" return;="" }="" }="" }="" *="" *="" 获取速度跟踪器="" *="" *="" @param="" event="" */="" private="" void="" obtainvelocitytracker(motionevent="" event)="" {="" if="" (!isscroll)="" return;="" if="" (mtracker="=" null)="" {="" mtracker="VelocityTracker.obtain();" }="" mtracker.addmovement(event);="" }="" *="" *="" 回收速度跟踪器="" */="" private="" void="" recyclevelocitytracker()="" {="" if="" (mtracker="" !="null)" {="" mtracker.recycle();="" mtracker="null;" }="" }="" *="" *="" 根据用户输入显示类型,在滑动时在不同的位置显示提示框="" */="" private="" int="" getselectindexfromshowtype(int="" showpositiontype)="" {="" int="" visiblescale="(width" -="" mxori)="" interval;="" switch="" (showpositiontype)="" {="" case="" first:="" mselectmiddle="1;" return="" mselectmiddle;="" case="" middle:="" if="" (mxdata.size()=""><= visiblescale)="" {="" mselectmiddle="middleIndex(mXData.size());" }="" else="" {="" mselectmiddle="middleIndex(visibleScale);" }="" return="" mselectmiddle;="" 屏幕可显示的刻度="" case="" end:="" if="" (mxdata.size()=""><= visiblescale)="" {="" mselectmiddle="mXData.size();" }="" else="" {="" mselectmiddle="visibleScale;" }="" return="" visiblescale;="" default:="" mselectmiddle="0;" return="" mselectmiddle;="" }="" }="" public="" void=""> value) {
        this.mSpinnerValue = value;
        invalidate();
    }
 
    public void setValue(Map value, List xValue, List yValue) {
        this.mSpinnerValue = value;
        this.mXData = xValue;
        this.mYData = yValue;
        invalidate();
    }
 
 
    public Map getValue() {
        return mSpinnerValue;
    }
 
    /**
     * 获取丈量文本的矩形
     *
     * @param text
     * @param paint
     * @return
     */
    private Rect getTextBounds(String text, Paint paint) {
        Rect rect = new Rect();
        paint.getTextBounds(text, 0, text.length(), rect);
        return rect;
    }
 
    /**
     * dp转化成为px
     *
     * @param dp
     * @return
     */
    private int dpToPx(int dp) {
        float density = getContext().getResources().getDisplayMetrics().density;
        return (int) (dp * density + 0.5f * (dp >= 0 ? 1 : -1));
    }
 
    /**
     * sp转化为px
     *
     * @param sp
     * @return
     */
    private int spToPx(int sp) {
        float scaledDensity = getContext().getResources().getDisplayMetrics().scaledDensity;
        return (int) (scaledDensity * sp + 0.5f * (sp >= 0 ? 1 : -1));
    }
 
    /**
     * 获取集合中最长的index
     */
    private static final int NULL_INDEX = -1;
 
    public int getListItemMaxIndex(List data) {
        if (data == null || data.size() < 1)="" {="" return="" null_index;="" }="" int="" max="(data.get(0)" +="" "").length();="" for="" (int="" i="0;" i="">< data.size();="" i++)="" {="" string="" s="data.get(i)" +="" "";="" if="" (s.length()=""> max) {
                return i;
            }
        }
        return NULL_INDEX;
    }
 
    //获得在滑动结束的时候在屏幕内的点
    private int middleIndex(int size) {
        if (size % 2 == 0) {
            return size / 2;
        } else {
            return size / 2 + 1;
        }
    }
 
 
    /**
     * 根据两点坐标获取中间某个点
     *
     * @param from 坐标1
     * @param to   坐标2
     */
 
    //获取已知点的斜率 y = kx+b
    private float getSlope(Point from, Point to) {
        float k = (to.y - from.y) / (to.x - from.x);
        Log.e("Point", "参数b:" + k);
        return k;
    }
 
    //获取参数 b
    private float getParams(Point from, Point to) {
        float b = from.y - (getSlope(from, to) * from.x);
        Log.e("Point", "参数b:" + b);
        return b;
    }
 
    //根据两点间的坐标获取x轴的任意一个坐标x值,
    private float getArbitrarilyX(Point from, Point to, int grade, int needGrade) {
        //获得输入的新坐标
        float x = ((to.x - from.x) * needGrade) / grade + from.x;
        Log.e("Point", "x坐标值:" + x);
        return x;
    }
 
    //获取坐标值
    private Point getPoint(Point from, Point to, int grade, int needGrade) {
        Point point = new Point();
        point.setX(getArbitrarilyX(from, to, grade, needGrade));
        float slope = getSlope(from, to);
        point.setY(slope * point.x + getParams(from, to));
        return point;
    }
 
    //获取绘制折线的点
    private Point getSpinnerPoint(int valueIndex) {
        float x = mXInit + interval * (valueIndex);
        float y = mYOri - mYOri * (1 - 0.1f) * mSpinnerValue.get(mXData.get(valueIndex)) / mYData.get(mYData.size() - 1);
        return new Point(x, y);
    }
 
    private class Point {
        float x;
        float y;
 
        public Point() {
        }
 
        public float getX() {
            return x;
        }
 
        public void setX(float x) {
            this.x = x;
        }
 
        public float getY() {
            return y;
        }
 
        public void setY(float y) {
            this.y = y;
        }
 
        public Point(float x, float y) {
            this.x = x;
            this.y = y;
        }
 
        @Override
        public String toString() {
            return "Point{" +
                    "x=" + x +
                    ", y=" + y +
                    '}';
        }
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助。

软件
前端设计
程序设计
Java相关