Android开发之天气趋势折线图

先来看下效果:

控件内容比较简单,就是一个普通的折线图,上下分别带有数字,点击的时候显示当天温度的差值。

创建一个类继承自View,并添加两个构造方法:

public class TrendGraph extends View {
  public TrendGraph(Context context) { // 在java代码中创建调用
    super(context);
  }

  public TrendGraph(Context context, AttributeSet attrs) { // 在xml中创建调用
    super(context, attrs);
  }
} 

因为这里不需要考虑wrap_content的情况,所以onMeasure方法不需重写,关键的是onDraw,而onDraw方法其实也不困难,只需要确定好每个点的具体位置就好,因为连线也是需要点的坐标,代码比较啰嗦,可以略过:

   @Override
   protected void onDraw(Canvas canvas) {
     super.onDraw(canvas);
     if (mElements == null || mElements.size() == 0) {
       return;
     }
     double max_up = getMaxUp();
     double min_down = getMinDown();
     canvas.setDrawFilter(mDrawFilter);
     mPaint.setStrokeWidth(lineWeith);
     float width = getWidth();
     float grap = width / mElements.size();
     float textSize = mTextPaint.getTextSize();
     int textMargin = circleRadius * 2;
     float margin_top = textSize + 2 * textMargin;
     Log.d(TAG, "onDraw: " + margin_top + "|" + textSize);
     float height = getHeight() - 2 * margin_top;

     for (int i = 0; i < mElements.size() - 1; i++) {
       float startX = i * grap + grap / 2;
       float stopX = (i + 1) * grap + grap / 2;
       float startY = (float) (max_up - mElements.get(i).getUp()) / (float) (max_up -
           min_down) * height + margin_top;
       float stopY = (float) (max_up - mElements.get(i + 1).getUp()) / (float) (max_up -
           min_down) * height + margin_top;

       canvas.drawText((int) mElements.get(i).getUp() + "℃", startX - textSize, startY -
           textMargin, mTextPaint);
       canvas.drawCircle(startX, startY, circleRadius, mPaint);
       canvas.drawLine(startX, startY, stopX, stopY, mPaint);
       if (i == mElements.size() - 2) {
         canvas.drawText((int) mElements.get(i + 1).getUp() + "℃", stopX - textSize, stopY
             - textMargin, mTextPaint);
         canvas.drawCircle(stopX, stopY, circleRadius, mPaint);
       }

       startY = (float) (max_up - mElements.get(i).getDown()) / (float) (max_up - min_down) *
           height + margin_top;
       stopY = (float) (max_up - mElements.get(i + 1).getDown()) / (float) (max_up -
           min_down) * height + margin_top;
       canvas.drawText((int) mElements.get(i).getDown() + "℃", startX - textSize, startY +
           textSize + textMargin, mTextPaint);
       canvas.drawCircle(startX, startY, circleRadius, mPaint);
       canvas.drawLine(startX, startY, stopX, stopY, mPaint);
       if (i == mElements.size() - 2) {
         canvas.drawText((int) mElements.get(i + 1).getDown() + "℃", stopX - textSize,
             stopY + textSize + textMargin, mTextPaint);
         canvas.drawCircle(stopX, stopY, circleRadius, mPaint);
       }
     }
   }

考虑到需要允许用户进行简单的设置,例如点的大小,文字大小等等,所以定义一些自定义属性(res/values/attr.xml):

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <declare-styleable name="TrendGraph">
    <attr name="lineWidth" format="dimension"/>
    <attr name="circleRadius" format="dimension" />
    <attr name="textSize" format="dimension" />
    <attr name="textColor" format="reference" />
  </declare-styleable>
</resources>

format指该属性的格式,指定为dimension则是尺寸,取值单位是dp、sp或px等等,而reference则是引用,即一般在xml中引用其他资源的写法,如@string/app_name。还有其他类型,可以自行查找文档。

对自定义属性进行解析得到,这个解析需要在上面定义的第二个构造方法中进行,代码如下:

  public TrendGraph(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.TrendGraph);
    circleRadius = array.getDimensionPixelSize(R.styleable.TrendGraph_circleRadius, 5);
    lineWeith = array.getDimensionPixelSize(R.styleable.TrendGraph_lineWidth, 3);
    mTextPaint.setTextSize(array.getDimensionPixelSize(R.styleable.TrendGraph_textSize, 35));
    mTextPaint.setColor(array.getColor(R.styleable.TrendGraph_textColor, Color.BLACK));
    array.recycle();
  }

getDimensionPixelSize方法则是通过传入的值,转换为具体的像素(px)值,也就免去我们手动转换的麻烦。但是要注意,其中的defaultValue依然是px。

接着,就可以通过xml指定这些属性,在布局中加入命名空间:

xmlns:app=http://schemas.android.com/apk/res-auto

Android Studio会自动引入,并且可以补全得到,具体使用:

  <com.fndroid.byweather.views.TrendGraph
    android:id="@+id/tg"
    android:layout_width="match_parent"
    app:textColor="@color/colorAccent"
    app:textSize="22sp"
    app:circleRadius="2dp"
    android:layout_height="200dp"/>

最后,添加一个事件监听,在点击View的时候进行回调:

① 定义接口:

  public interface onItemClickListener{
    void onItemClick(View view, Element element);
  }

② 在View中添加接口对象,并设置setter方法:

public class TrendGraph extends View {

  private onItemClickListener mOnItemClickListener;

  // 省略代码

  public void setOnItemClickListener(onItemClickListener onItemClickListener) {
    mOnItemClickListener = onItemClickListener;
  }

} 

③ 处理onTouchEvent,重写该方法,代码如下:

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    int viewWidth = getWidth();
    int itemWidth = viewWidth / mElements.size();
    int viewHeight = getHeight();
    boolean isMove = false; // 界面中最外层为一个NestedScrollView,所以为了避免滑动时也触发,加入变量处理

    switch (event.getAction()) {
      case MotionEvent.ACTION_MOVE:
        isMove = true;
        break;
      case MotionEvent.ACTION_UP:
        if (!isMove){ // 判断只有点击时进行回调
          int position = (int) (event.getX() / itemWidth); // 取得点击的位置
          mOnItemClickListener.onItemClick(this, mElements.get(position)); // 回调
        }
        break;
    }

    return true;
  }

④ 在Activity中,进行监听设置,并处理:

  historyGraph.setOnItemClickListener(this);
  @Override
  public void onItemClick(View view, TrendGraph.Element element) {
    int dt = (int) (element.getUp() - element.getDown());
    Snackbar.make(root, "当天温差为:" + dt + "℃", Snackbar.LENGTH_SHORT).show();
  }

总结

效果完成!如果有疑问欢迎大家交流讨论,希望本文对大家开发Android能有所帮助。

(0)

相关推荐

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

    继续练习自定义View,这次带来的是简易折线图,支持坐标点点击监听,效果如下: 画坐标轴.画刻度.画点.连线..x.y轴的数据范围是写死的 1 <= x <= 7 ,1 <= y <= 70 ..写活的话涉及到坐标轴刻度的动态计算.坐标点的坐标修改,想想就头大,这里只练习自定义View. 1.在res/values文件夹下新建attrs.xml文件,编写自定义属性: <?xml version="1.0" encoding="utf-8"

  • Android自定义View实现折线图效果

    下面就是结果图(每种状态用一个表情图片表示): 一.主页面的布局文件如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height=&quo

  • 详解Android图表 MPAndroidChart折线图

    1.介绍 MPAndroidChart GitHub地址 MPAndroidChart的强大之处就不在多说了,目前最新的版本是3.0.1,在新版本中很多方法都被弃用了,这个要注意一下,在网上查到的大多数资料都是关于旧版本的,今天来实现一下折线图,把过程记录下来,分享给大家. 效果图: 2.引入开源库 在项目根目录的build.gradle文件中加入如下代码 allprojects { repositories { maven { url "https://jitpack.io" } }

  • MPAndroidChart开源图表库的使用介绍之饼状图、折线图和柱状图

    MPAndroidChart开源图表库之饼状图 为大家介绍一款图标开源库MPAndroidChart,它不仅可以在Android设备上绘制各种统计图表,而且可以对图表进行拖动和缩放操作,用起来非常灵活.MPAndroidChart同样拥有常用的图表类型:线型图.饼图.柱状图和散点图. mpandroidchartlibrary.jar包下载地址: https://github.com/PhilJay/MPAndroidChart/releases 下面主要实现以下饼状图: 1.从上面的地址中下载

  • Android开发之天气趋势折线图

    先来看下效果: 控件内容比较简单,就是一个普通的折线图,上下分别带有数字,点击的时候显示当天温度的差值. 创建一个类继承自View,并添加两个构造方法: public class TrendGraph extends View { public TrendGraph(Context context) { // 在java代码中创建调用 super(context); } public TrendGraph(Context context, AttributeSet attrs) { // 在xm

  • Android自定义View之渐变色折线图的实现

    目录 前言 如何实现 总结 前言 在之前的项目中,有做过一个需求,需要实现一个颜色渐变的折线图.当时项目中使用的图表库是MPAndroidChart,但是该库没有提供合适的方法来实现想要的效果,因此只能通过自定义view来实现. 通过这篇文章记录一下,便于之后需要实现类似的效果时查找使用. 如何实现 通过创建LinearGradient来实现颜色渐变,并将之设置到画笔Paint的着色器Shader,绘制想要的路径即可实现该效果. 实现代码如下: class GradientLineChart :

  • Android自定义View实现天气预报折线图

    本文实例为大家分享了Android自定义View画天气预报折线图的具体代码,供大家参考,具体内容如下 效果图如下: 刚开始尝试用第三方画曲线的框架来画效果图,后来发现曲线间的阴影当有负数的度数的时候画不出来,而且不需要点击放大.点点可点的效果,用框架显得很臃肿,所以最后用自定义View来画的折线图.自定义画折线图的大致思路:这个图是有多个四边形组成的(4个点连接起来就是一个四边形),两边延伸:添加四个多余的点,将左右的边距设置成负数即可. 代码如下: public class WeatherCh

  • ios开发一个好看的折线图

    一:介绍 在项目中遇到数据展示需求时,往往会通过,以列表的形式展示出数据或者以表格的形式展示.但是并不能直观的观察数据的变化,如果通过图表的形式来展示,就可以更快捷的获取到数据变化情况. 图表展示的方式大致分为折线图.柱状图.饼状图等等,那么如何码出一个高颜值原生折线图呢?demo源码已经放在GitHub上,下面来介绍一下如何使用. 二:项目展示 运行后的展示截图如下: 三: 实现思路分析 实现折线图的核心代码是下面四个类: FBYLineGraphBaseView FBYLineGraphCo

  • 安卓(Android)开发之自定义饼状图

    先来看看效果图 先分析饼状图的构成,非常明显,饼状图就是一个又一个的扇形构成的,每个扇形都有不同的颜色,对应的有名字,数据和百分比. 经以上信息可以得出饼状图的最基本数据应包括:名字 数据值 百分比 对应的角度 颜色. 用户关心的数据 : 名字 数据值 百分比 需要程序计算的数据: 百分比 对应的角度 其中颜色这一项可以用户指 public class PieData { private String name; // 名字 private float value; // 数值 private

  • 使用Android原生WebView+Highcharts实现可左右滑动的折线图

    目录 前言 开发的思路如下: (一)设计Android端的View层 (二)设计与JS交互的方法 (三)开发html以及js逻辑 总结 前言 今天的内容是使用Android原生webview配合Highcharts开发折线图左右滑动的功能,折线图有很多优秀的第三方库可以使用,比如MPAndroidChart.Highcharts,MPAndroidChart可以通过拉伸折线图界面进行滑动折线图,亲测有效,现在我要讲的是如何使用内嵌html页面进行滑动折线图的开发.效果以及源码目录结构如下图,源码

  • Android自动缩放上下限折线图示例

    目录 正文 AutoLineChart完整代码 正文 一条折线,根据最大最小值自动缩放上下限. 继承View 数据使用FloatBuffer存储 可改变显示窗口的大小 可指定坐标轴,折线和字体颜色 AutoLineChart完整代码 import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import

  • Android开发实现绘制淘宝收益图折线效果示例

    本文实例讲述了Android开发实现绘制淘宝收益图折线效果.分享给大家供大家参考,具体如下: 实现的效果我一会贴上,我先说下原理,我们知道要实现在canvas上画线,不就是要搞一个paint嘛,然后首先肯定要设置下paint的属性,那么画文字呢,不就是Textpaint吗,对,就是这么简单,接下来怎么画,折线图主要分为X轴和y轴,x轴表示日期,y表示收益,好,说道这里,大家应该知道怎么去做了,下面直接贴代码 这个方法是,画x,y坐标系的,以及上面的日期和收益了 private void draw

  • Android开发自定义控件之折线图实现方法详解

    本文实例讲述了Android开发自定义控件之折线图实现方法.分享给大家供大家参考,具体如下: 前言 折线图是Android开发中经常会碰到的效果,但由于涉及自定义View的知识,对许多刚入门的小白来说会觉得很高深.其实不然,接下来我就以尽量通俗的语言来说明下图折线图效果的实现过程. 效果图 实现过程 首先,选择自定义控件的方式. 自定义控件的实现有四种方式: 1.继承View,重写onDraw.onMeasure等方法. 2.继承已有的View(比如TextView). 3.继承ViewGrou

  • Android开发RecyclerView实现折线图效果

    本文实例为大家分享了Android开发RecyclerView实现折线图效果的具体代码,供大家参考,具体内容如下 效果图如下: 实现的关键是自定义的控件: package com.example.recyclelinechart.test; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; imp

随机推荐