返回顶部
首页 > 资讯 > 移动开发 >Android自定义View简易折线图控件(二)
  • 203
分享到

Android自定义View简易折线图控件(二)

折线图viewAndroid 2022-06-06 11:06:11 203人浏览 安东尼
摘要

继续练习自定义View,这次带来的是简易折线图,支持坐标点点击监听,效果如下: 画坐标轴、画刻度、画点、连线。。x、y轴的数据范围是写死的 1 <= x <= 7

继续练习自定义View,这次带来的是简易折线图,支持坐标点点击监听,效果如下:

这里写图片描述

画坐标轴、画刻度、画点、连线。。x、y轴的数据范围是写死的 1 <= x <= 7 ,1 <= y <= 70 。。写活的话涉及到坐标轴刻度的动态计算、坐标点的坐标修改,想想就头大,这里只练习自定义View。

1、在res/values文件夹下新建attrs.xml文件,编写自定义属性:


<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="LineChartView">
 <attr name="textColor" fORMat="color" />
 <attr name="lineColor" format="color" />
 <attr name="pointColor" format="color" />
 </declare-styleable>
</resources>

2、新建LineChartView继承View,重写构造方法:


 public LineChartView(Context context) {
  this(context, null);
 }
 public LineChartView(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
 }
 public LineChartView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
 }

3、在第三个构造方法中获取自定义属性的值:


 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LineChartView, defStyleAttr, 0);
 mTextColor = ta.getColor(R.styleable.LineChartView_textColor, 0xff381a59);
 mLineColor = ta.getColor(R.styleable.LineChartView_lineColor, 0xff8e29fa);
 mPointColor = ta.getColor(R.styleable.LineChartView_pointColor, 0xffff5100);
 mPointRadius = DensityUtils.dp2px(context, 3);
 ta.recycle();

4、创建画图所使用的对象,如Paint、Path:


 mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mTextPaint.setStyle(Paint.Style.FILL);
 mTextPaint.setColor(mTextColor);
 mTextPaint.setTextSize(40);
 mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mLinePaint.setStyle(Paint.Style.STROKE);
 mLinePaint.setColor(mLineColor);
 mLinePaint.setStrokeWidth(DensityUtils.dp2px(context, 2));
 mLinePaint.setStrokeCap(Paint.Cap.ROUND);
 mXyPath = new Path();
 mPointPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mPointPaint.setStyle(Paint.Style.FILL);
 mPointPaint.setColor(mPointColor);
 mPointCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mPointCirclePaint.setStyle(Paint.Style.STROKE);
 mPointCirclePaint.setStrokeWidth(DensityUtils.dp2px(context, 2));
 mPointCirclePaint.setColor(mLineColor);

5、重写onMeasure()方法,计算自定义View的宽高:


 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  setMeasuredDimension(measuredDimension(widthMeasureSpec), measuredDimension(heightMeasureSpec));
 }
 private int measuredDimension(int measureSpec) {
  int result;
  int mode = MeasureSpec.getMode(measureSpec);
  int size = MeasureSpec.getSize(measureSpec);
  if (mode == MeasureSpec.EXACTLY) {
   result = size;
  } else {
   result = 500;
   if (mode == MeasureSpec.AT_MOST) {
    result = Math.min(result, size);
   }
  }
  return result;
 }

6、暴露一个设置x、y数据集合的方法:


 
 public void setDataList(List<Integer> xList, List<Integer> yList) {
  if (xList == null || yList == null || xList.size() == 0 || yList.size() == 0) {
   throw new IllegalArgumentException("没有数据");
  }
  if (xList.size() != yList.size()) {
   throw new IllegalArgumentException("x、y轴数据长度不一致");
  }
  setPointData(xList, yList);
  setPointAnimator();
 }
 
 private void setPointData(List<Integer> xList, List<Integer> yList) {
  mPointList = new ArrayList<>();
  for (int i = 0; i < xList.size(); i++) {
   ChartPoint point = new ChartPoint();
   //设置坐标点的xy数据
   point.setxData(xList.get(i));
   point.setyData(yList.get(i));
   //计算坐标点的横纵坐标
   point.setX(xyMargin + xList.get(i) * (getWidth() - 2 * xyMargin) / maxX);
   point.setY(getHeight() - xyMargin - (getHeight() - 2 * xyMargin) * yList.get(i) / maxY);
   mPointList.add(point);
  }
 }
 
 private void setPointAnimator() {
  for (int i = 0; i < mPointList.size(); i++) {
   final ChartPoint point = mPointList.get(i);
   ValueAnimator anim;
   if (mLastPointList != null && mLastPointList.size() > 0) {
    anim = ValueAnimator.ofInt(mLastPointList.get(i).getY(), point.getY());
   } else {
    anim = ValueAnimator.ofInt(getHeight() - xyMargin, point.getY());
   }
   anim.setDuration(500);
   anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
     int value = (int) animation.getAnimatedValue();
     point.setY(value);
     invalidate();
    }
   });
   anim.start();
  }
  //储存坐标点集合
  mLastPointList = mPointList;
 }

7、重写onDraw()方法,绘制坐标轴、刻度,画点连线,注意坐标的计算:


 @Override
 protected void onDraw(canvas canvas) {
  super.onDraw(canvas);
  if (mPointList == null || mPointList.size() == 0) {
   return;
  }
  mXyPath.reset();
  mXyPath.moveTo(xyMargin, 0);
  mXyPath.lineTo(xyMargin, getHeight() - xyMargin);
  mXyPath.lineTo(getWidth(), getHeight() - xyMargin);
  canvas.drawPath(mXyPath, mLinePaint);//画x、y坐标轴
  for (int i = 0; i < mPointList.size(); i++) {
   //画x轴刻度线
   int x = xyMargin + (i + 1) * (getWidth() - 2 * xyMargin) / mPointList.size();
   canvas.drawLine(x, getHeight() - xyMargin - graduatedLineLength, x, getHeight() - xyMargin, mLinePaint);
   //画y轴刻度线
   int y = getHeight() - xyMargin - (i + 1) * (getHeight() - 2 * xyMargin) / mPointList.size();
   canvas.drawLine(xyMargin, y, xyMargin + graduatedLineLength, y, mLinePaint);
   //画坐标轴刻度文本
   canvas.drawText(String.valueOf(mPointList.get(i).getxData()), x, getHeight() - mTextPaint.getTextSize() / 4, mTextPaint);
   canvas.drawText(String.valueOf((i + 1) * 10), 0, y + mTextPaint.getTextSize() / 2, mTextPaint);
  }
  //画连接线
  for (int i = 0; i < mPointList.size(); i++) {
   if (i != mPointList.size() - 1) {
    ChartPoint lastP = mPointList.get(i);
    ChartPoint nextP = mPointList.get(i + 1);
    canvas.drawLine(lastP.getX(), lastP.getY(), nextP.getX(), nextP.getY(), mLinePaint);
   }
  }
  //画坐标点
  for (int i = 0; i < mPointList.size(); i++) {
   ChartPoint point = mPointList.get(i);
   canvas.drawCircle(point.getX(), point.getY(), mPointRadius, mPointPaint);
   canvas.drawCircle(point.getX(), point.getY(), mPointRadius, mPointCirclePaint);
  }
 }

8、设置坐标点点击事件:


 private OnPointClickListener mOnPointClickListener;
 
 public interface OnPointClickListener {
  
  void onPointClick(int index, ChartPoint point);
 }
 public void setOnPointClickListener(OnPointClickListener onPointClickListener) {
  mOnPointClickListener = onPointClickListener;
 }

9、重写onTouchEvent()方法,判断当前点击的点是不是在坐标点范围内:


 @Override
 public boolean onTouchEvent(MotionEvent event) {
  switch (event.getAction()) {
   case MotionEvent.ACTION_DOWN:
    //判断当前点击的点是否在坐标点范围内
    int curX = (int) event.getX();
    int curY = (int) event.getY();
    for (int i = 0; i < mPointList.size(); i++) {
     ChartPoint point = mPointList.get(i);
     double d1 = Math.pow(curX - point.getX(), 2);
     double d2 = Math.pow(curY - point.getY(), 2);
     //√ ̄(curX - cx)² + (curY - cy)² < R
     if (Math.sqrt(d1 + d2) < mPointRadius + 10) {//为了方便点击,把坐标点范围增大了10像素
      if (mOnPointClickListener != null) {
       mOnPointClickListener.onPointClick(i, point);
      }
     }
    }
    break;
  }
  return super.onTouchEvent(event);
 }

10、在activity_main.xml布局文件中使用该View:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="Http://schemas.android.com/apk/res/android"
 xmlns:lcv="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:gravity="center_horizontal"
 android:orientation="vertical"
 tools:context=".MainActivity">
 <com.monkey.linechartview.LineChartView
  android:id="@+id/chartView"
  android:layout_width="250dp"
  android:layout_height="250dp"
  android:layout_marginTop="@dimen/activity_vertical_margin"
  lcv:lineColor="#8e29fa"
  lcv:pointColor="#ff5100"
  lcv:textColor="#000000" />
 <Button
  android:id="@+id/btn"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_marginTop="@dimen/activity_vertical_margin"
  android:text="set data"
  android:textAllCaps="false" />
</LinearLayout>

11、在MainActivity.java中传入数据集合,并设置坐标点点击监听:


 btn.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
   List<Integer> xList = new ArrayList<>();
   List<Integer> yList = new ArrayList<>();
   for (int i = 0; i < 7; i++) {
    xList.add(i + 1);
    int y = (int) (Math.random() * 70 + 1);
    yList.add(y);
   }
   chartView.setDataList(xList, yList);
  }
 });
 chartView.setOnPointClickListener(new LineChartView.OnPointClickListener() {
  @Override
  public void onPointClick(int position, ChartPoint point) {
   tv.setText("position:" + position + "\nx:" + point.getxData() + "\ny:" + point.getyData());
  }
});

致此大致步骤完成了,发现和上一篇步骤差不多。。代码已上传GitHub
https://github.com/MonkeyMushroom/LineChartView/tree/master

您可能感兴趣的文章:Android自定义可左右滑动和点击的折线图Android绘制动态折线图Android自定义控件实现折线图Android HelloChart开源库图表之折线图的实例代码Android MPAndroidChart开源库图表之折线图的实例代码Android开发实现绘制淘宝收益图折线效果示例详解Android图表 MPAndroidChart折线图Android自定义View实现折线图效果Android开发之天气趋势折线图MPAndroidChart开源图表库的使用介绍之饼状图、折线图和柱状图Android实现折线走势图


--结束END--

本文标题: Android自定义View简易折线图控件(二)

本文链接: https://lsjlt.com/news/28262.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Android自定义View简易折线图控件(二)
    继续练习自定义View,这次带来的是简易折线图,支持坐标点点击监听,效果如下: 画坐标轴、画刻度、画点、连线。。x、y轴的数据范围是写死的 1 <= x <= 7...
    99+
    2022-06-06
    折线图 view Android
  • Android 实现自定义折线图控件
    目录前言概述原点计算Y轴宽度计算X轴高度X轴绘制轴线X轴刻度间隔网格线、文本Y轴计算Y轴分布刻度间隔、网格线、文本折线代码前言 日前,有一个“折现图”的需求,...
    99+
    2024-04-02
  • Android自定义View实现折线图效果
    下面就是结果图(每种状态用一个表情图片表示): 一、主页面的布局文件如下: <RelativeLayout xmlns:android="http://schema...
    99+
    2022-06-06
    折线图 view Android
  • Android怎么实现自定义折线图控件
    这篇“Android怎么实现自定义折线图控件”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android怎么实现自定义折线图...
    99+
    2023-07-02
  • Android自定义折线图控件的完整步骤
    目录前言概述原点计算Y轴宽度计算X轴高度X轴绘制轴线X轴刻度间隔网格线、文本Y轴计算Y轴分布刻度间隔、网格线、文本折线代码总结前言 日前,有一个“折现图&rdquo...
    99+
    2022-06-07
    折线图 Android
  • Android自定义View实现天气预报折线图
    本文实例为大家分享了Android自定义View画天气预报折线图的具体代码,供大家参考,具体内容如下 效果图如下: 刚开始尝试用第三方画曲线的框架来画效果图,后来发现曲线间的阴影当...
    99+
    2024-04-02
  • Android自定义View弧线进度控件
    这个是一个以弧线为依托的进度控件,主要包括了两个圆弧、一个圆、一个文本。   当我们点击开始按钮的时候,会出现一个动画,逐渐的出现进度,好了,下面开始我们的编码。 ...
    99+
    2022-06-06
    view Android
  • Android自定义View之渐变色折线图的实现
    目录前言如何实现总结前言 在之前的项目中,有做过一个需求,需要实现一个颜色渐变的折线图。当时项目中使用的图表库是MPAndroidChart,但是该库没有提供合适的方法来实现想要的效...
    99+
    2024-04-02
  • Android怎么自定义View实现渐变色折线图
    这篇文章主要介绍“Android怎么自定义View实现渐变色折线图”,在日常操作中,相信很多人在Android怎么自定义View实现渐变色折线图问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Android怎么...
    99+
    2023-06-30
  • 自定义视图view的折线图使用讲解
    目录一、如何绘制X和Y轴。1、我们来分析下,我们想知道三个坐标,那么这三个坐标是多少呢,我们该怎么计算呢? 答:这里,我是在onSizeChanged()方法中获取到了父类控件的宽度...
    99+
    2023-05-14
    自定义视图 自定义view 自定义view折线图
  • 自定义视图view的折线图怎么使用
    这篇文章主要讲解了“自定义视图view的折线图怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“自定义视图view的折线图怎么使用”吧!绘制折线图预览图绘制这个折线图需要都需要哪些步骤?...
    99+
    2023-07-05
  • Android自定义View实现简易画板功能
    本文实例为大家分享了Android自定义View实现简易画板的具体代码,供大家参考,具体内容如下 自定义VIew实现简易画板效果,功能包括清空、选择颜色,选择大小,效果如下 画板布...
    99+
    2024-04-02
  • android自定义View之复合控件
    复合控件可以很好地创建出具有重用功能的控件集合。 很多的APP都有一些共通的UI界面,为了统一应用程序的风格,下面我们就以一个Topbar为实例讲解复合控件。 实现效果如图: 第一...
    99+
    2024-04-02
  • android自定义控件实现简易时间轴(2)
    这篇做了一个简单的时间轴控件。右侧的数据就是一个简单的字符串。问题还是有的,当右侧的文字长度不一样的时候就会有问题了。现在可以修改一下适配右侧的文字。 效果如下: 代码: priv...
    99+
    2024-04-02
  • android自定义控件实现简易时间轴(1)
    本文实例为大家分享了android自定义控件实现简易时间轴的具体代码,供大家参考,具体内容如下 之前项目需要写一个消费记录,类似于时间轴似的控件,自身在自定义控件这里不咋地(&hel...
    99+
    2024-04-02
  • Android自定义控件之自定义属性(二)
    前言: 上篇介绍了自定义控件的基本要求以及绘制的基本原理,本篇文章主要介绍如何给自定义控件自定义一些属性。本篇文章将继续以上篇文章自定义圆形百分比为例进行讲解。有关原理知识请参...
    99+
    2022-06-06
    属性 自定义属性 Android
  • Android自定义View实现多图片选择控件
    前言 相信很多朋友在开发中都会遇到图片上传的情况,尤其是多图上传,最经典的莫过于微信的图片选择了。所有很多情况下会使用到多图选择,所以就有了这篇文章,今天抽点时间写了个控件。 ...
    99+
    2022-06-06
    view 选择 图片 Android
  • Android如何自定义View歌词控件
    本篇内容介绍了“Android如何自定义View歌词控件”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!目录前言一、 歌词解析歌词实体类Lrc...
    99+
    2023-06-20
  • android自定义控件如何实现简易时间轴
    这篇“android自定义控件如何实现简易时间轴”除了程序员外大部分人都不太理解,今天小编为了让大家更加理解“android自定义控件如何实现简易时间轴”,给大家总结了以下内容,具有一定借鉴价值,内容详细步骤清晰,细节处理妥当,希望大家通过...
    99+
    2023-06-28
  • Android自定义控件实现简单的轮播图控件
    最近要做一个轮播图的效果,网上看了几篇文章,基本上都能找到实现,效果还挺不错,但是在写的时候感觉每次都要单独去重新在Activity里写一堆代码。于是自己封装了一下。本篇轮播图...
    99+
    2022-06-06
    轮播图 轮播 Android
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作