Android自定义可左右滑动和点击的折线图

前言

前几天有小盆友让我写一个折线图,可以点击,可以左右滑动。对于折线肯定有很多项目都使用过,所以网上肯定也有很多demo,像AndroidChart、HelloChart之类的,功能相当丰富,效果也很赞,但是太重了,其他的小demo又不符合要求,当然了,我写的自定义折线图的思想也有来自这些小demo,对他们表示感谢。

效果图

废话不多说,先上效果图:

效果是不是很赞,如果上图满足你的需求,那就继续往下看。

自定义折线图的步骤:

1、自定义view所需要的属性

确定所需要的自定义view的属性,然后在res/values目录下,新建一个attrs.xml文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <!-- xy坐标轴颜色 -->
 <attr name="xylinecolor" format="color" />
 <!-- xy坐标轴宽度 -->
 <attr name="xylinewidth" format="dimension" />
 <!-- xy坐标轴文字颜色 -->
 <attr name="xytextcolor" format="color" />
 <!-- xy坐标轴文字大小 -->
 <attr name="xytextsize" format="dimension" />
 <!-- 折线图中折线的颜色 -->
 <attr name="linecolor" format="color" />
 <!-- x轴各个坐标点水平间距 -->
 <attr name="interval" format="dimension" />
 <!-- 背景颜色 -->
 <attr name="bgcolor" format="color" />
 <!--是否在ACTION_UP时,根据速度进行自滑动,建议关闭,过于占用GPU-->
 <attr name="isScroll" format="boolean" />
 <declare-styleable name="chartView">
  <attr name="xylinecolor" />
  <attr name="xylinewidth" />
  <attr name="xytextcolor" />
  <attr name="xytextsize" />
  <attr name="linecolor" />
  <attr name="interval" />
  <attr name="bgcolor" />
  <attr name="isScroll" />
 </declare-styleable>
</resources>

2、在自定义view的构造方法中获取我们的自定义属性:

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();
 }

 /**
  * 初始化
  *
  * @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);
   switch (attr) {
    case R.styleable.chartView_xylinecolor://xy坐标轴颜色
     xylinecolor = array.getColor(attr, xylinecolor);
     break;
    case R.styleable.chartView_xylinewidth://xy坐标轴宽度
     xylinewidth = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, xylinewidth, getResources().getDisplayMetrics()));
     break;
    case R.styleable.chartView_xytextcolor://xy坐标轴文字颜色
     xytextcolor = array.getColor(attr, xytextcolor);
     break;
    case R.styleable.chartView_xytextsize://xy坐标轴文字大小
     xytextsize = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, xytextsize, getResources().getDisplayMetrics()));
     break;
    case R.styleable.chartView_linecolor://折线图中折线的颜色
     linecolor = array.getColor(attr, linecolor);
     break;
    case R.styleable.chartView_interval://x轴各个坐标点水平间距
     interval = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, interval, getResources().getDisplayMetrics()));
     break;
    case R.styleable.chartView_bgcolor: //背景颜色
     bgcolor = array.getColor(attr, bgcolor);
     break;
    case R.styleable.chartView_isScroll://是否在ACTION_UP时,根据速度进行自滑动
     isScroll = array.getBoolean(attr, isScroll);
     break;
   }
  }
  array.recycle();
 }
 /**
  * 初始化畫筆
  */
 private void initPaint() {
  xyPaint = new Paint();
  xyPaint.setAntiAlias(true);
  xyPaint.setStrokeWidth(xylinewidth);
  xyPaint.setStrokeCap(Paint.Cap.ROUND);
  xyPaint.setColor(xylinecolor);
  xyTextPaint = new Paint();
  xyTextPaint.setAntiAlias(true);
  xyTextPaint.setTextSize(xytextsize);
  xyTextPaint.setStrokeCap(Paint.Cap.ROUND);
  xyTextPaint.setColor(xytextcolor);
  xyTextPaint.setStyle(Paint.Style.STROKE);
  linePaint = new Paint();
  linePaint.setAntiAlias(true);
  linePaint.setStrokeWidth(xylinewidth);
  linePaint.setStrokeCap(Paint.Cap.ROUND);
  linePaint.setColor(linecolor);
  linePaint.setStyle(Paint.Style.STROKE);
 }

3、获取一写基本点

这些基本点包括:xy轴的原点坐标,第一个点的x轴的初始化坐标值以及其最大值和最小值。这些参数可以在onLayout()方法里面获取。

 @Override
 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
  if (changed) {
   //这里需要确定几个基本点,只有确定了xy轴原点坐标,第一个点的X坐标值及其最大最小值
   width = getWidth();
   height = getHeight();
   //Y轴文本最大宽度
   float textYWdith = getTextBounds("000", xyTextPaint).width();
   for (int i = 0; i < yValue.size(); i++) {//求取y轴文本最大的宽度
    float temp = getTextBounds(yValue.get(i) + "", xyTextPaint).width();
    if (temp > textYWdith)
     textYWdith = temp;
   }
   int dp2 = dpToPx(2);
   int dp3 = dpToPx(3);
   xOri = (int) (dp2 + textYWdith + dp2 + xylinewidth);//dp2是y轴文本距离左边,以及距离y轴的距离
//   //X轴文本最大高度
   xValueRect = getTextBounds("000", xyTextPaint);
   float textXHeight = xValueRect.height();
   for (int i = 0; i < xValue.size(); i++) {//求取x轴文本最大的高度
    Rect rect = getTextBounds(xValue.get(i) + "", xyTextPaint);
    if (rect.height() > textXHeight)
     textXHeight = rect.height();
    if (rect.width() > xValueRect.width())
     xValueRect = rect;
   }
   yOri = (int) (height - dp2 - textXHeight - dp3 - xylinewidth);//dp3是x轴文本距离底边,dp2是x轴文本距离x轴的距离
   xInit = interval + xOri;
   minXInit = width - (width - xOri) * 0.1f - interval * (xValue.size() - 1);//减去0.1f是因为最后一个X周刻度距离右边的长度为X轴可见长度的10%
   maxXInit = xInit;
  }
  super.onLayout(changed, left, top, right, bottom);
 }

4、利用ondraw()方法进行绘制

 @Override
 protected void onDraw(Canvas canvas) {
//  super.onDraw(canvas);
  canvas.drawColor(bgcolor);
  drawXY(canvas);
  drawBrokenLineAndPoint(canvas);
 }

 /**
  * 绘制折线和折线交点处对应的点
  *
  * @param canvas
  */
 private void drawBrokenLineAndPoint(Canvas canvas) {
  if (xValue.size() <= 0)
   return;
  //重新开一个图层
  int layerId = canvas.saveLayer(0, 0, width, height, null, Canvas.ALL_SAVE_FLAG);
  drawBrokenLine(canvas);
  drawBrokenPoint(canvas);
  // 将折线超出x轴坐标的部分截取掉
  linePaint.setStyle(Paint.Style.FILL);
  linePaint.setColor(bgcolor);
  linePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
  RectF rectF = new RectF(0, 0, xOri, height);
  canvas.drawRect(rectF, linePaint);
  linePaint.setXfermode(null);
  //保存图层
  canvas.restoreToCount(layerId);
 }
 /**
  * 绘制折线对应的点
  *
  * @param canvas
  */
 private void drawBrokenPoint(Canvas canvas) {
  float dp2 = dpToPx(2);
  float dp4 = dpToPx(4);
  float dp7 = dpToPx(7);
  //绘制节点对应的原点
  for (int i = 0; i < xValue.size(); i++) {
   float x = xInit + interval * i;
   float y = yOri - yOri * (1 - 0.1f) * value.get(xValue.get(i)) / yValue.get(yValue.size() - 1);
   //绘制选中的点
   if (i == selectIndex - 1) {
    linePaint.setStyle(Paint.Style.FILL);
    linePaint.setColor(0xffd0f3f2);
    canvas.drawCircle(x, y, dp7, linePaint);
    linePaint.setColor(0xff81dddb);
    canvas.drawCircle(x, y, dp4, linePaint);
    drawFloatTextBox(canvas, x, y - dp7, value.get(xValue.get(i)));
   }
   //绘制普通的节点
   linePaint.setStyle(Paint.Style.FILL);
   linePaint.setColor(Color.WHITE);
   canvas.drawCircle(x, y, dp2, linePaint);
   linePaint.setStyle(Paint.Style.STROKE);
   linePaint.setColor(linecolor);
   canvas.drawCircle(x, y, dp2, linePaint);
  }
 }
 /**
  * 绘制显示Y值的浮动框
  *
  * @param canvas
  * @param x
  * @param y
  * @param text
  */
 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, linePaint);
  linePaint.setColor(Color.WHITE);
  linePaint.setTextSize(spToPx(14));
  Rect rect = getTextBounds(text + "", linePaint);
  canvas.drawText(text + "", x - rect.width() / 2, y - dp6 - (dp18 - rect.height()) / 2, linePaint);
 }
 /**
  * 绘制折线
  *
  * @param canvas
  */
 private void drawBrokenLine(Canvas canvas) {
  linePaint.setStyle(Paint.Style.STROKE);
  linePaint.setColor(linecolor);
  //绘制折线
  Path path = new Path();
  float x = xInit + interval * 0;
  float y = yOri - yOri * (1 - 0.1f) * value.get(xValue.get(0)) / yValue.get(yValue.size() - 1);
  path.moveTo(x, y);
  for (int i = 1; i < xValue.size(); i++) {
   x = xInit + interval * i;
   y = yOri - yOri * (1 - 0.1f) * value.get(xValue.get(i)) / yValue.get(yValue.size() - 1);
   path.lineTo(x, y);
  }
  canvas.drawPath(path, linePaint);
 }
 /**
  * 绘制XY坐标
  *
  * @param canvas
  */
 private void drawXY(Canvas canvas) {
  int length = dpToPx(4);//刻度的长度
  //绘制Y坐标
  canvas.drawLine(xOri - xylinewidth / 2, 0, xOri - xylinewidth / 2, yOri, xyPaint);
  //绘制y轴箭头
  xyPaint.setStyle(Paint.Style.STROKE);
  Path path = new Path();
  path.moveTo(xOri - xylinewidth / 2 - dpToPx(5), dpToPx(12));
  path.lineTo(xOri - xylinewidth / 2, xylinewidth / 2);
  path.lineTo(xOri - xylinewidth / 2 + dpToPx(5), dpToPx(12));
  canvas.drawPath(path, xyPaint);
  //绘制y轴刻度
  int yLength = (int) (yOri * (1 - 0.1f) / (yValue.size() - 1));//y轴上面空出10%,计算出y轴刻度间距
  for (int i = 0; i < yValue.size(); i++) {
   //绘制Y轴刻度
   canvas.drawLine(xOri, yOri - yLength * i + xylinewidth / 2, xOri + length, yOri - yLength * i + xylinewidth / 2, xyPaint);
   xyTextPaint.setColor(xytextcolor);
   //绘制Y轴文本
   String text = yValue.get(i) + "";
   Rect rect = getTextBounds(text, xyTextPaint);
   canvas.drawText(text, 0, text.length(), xOri - xylinewidth - dpToPx(2) - rect.width(), yOri - yLength * i + rect.height() / 2, xyTextPaint);
  }
  //绘制X轴坐标
  canvas.drawLine(xOri, yOri + xylinewidth / 2, width, yOri + xylinewidth / 2, xyPaint);
  //绘制x轴箭头
  xyPaint.setStyle(Paint.Style.STROKE);
  path = new Path();
  //整个X轴的长度
  float xLength = xInit + interval * (xValue.size() - 1) + (width - xOri) * 0.1f;
  if (xLength < width)
   xLength = width;
  path.moveTo(xLength - dpToPx(12), yOri + xylinewidth / 2 - dpToPx(5));
  path.lineTo(xLength - xylinewidth / 2, yOri + xylinewidth / 2);
  path.lineTo(xLength - dpToPx(12), yOri + xylinewidth / 2 + dpToPx(5));
  canvas.drawPath(path, xyPaint);
  //绘制x轴刻度
  for (int i = 0; i < xValue.size(); i++) {
   float x = xInit + interval * i;
   if (x >= xOri) {//只绘制从原点开始的区域
    xyTextPaint.setColor(xytextcolor);
    canvas.drawLine(x, yOri, x, yOri - length, xyPaint);
    //绘制X轴文本
    String text = xValue.get(i);
    Rect rect = getTextBounds(text, xyTextPaint);
    if (i == selectIndex - 1) {
     xyTextPaint.setColor(linecolor);
     canvas.drawText(text, 0, text.length(), x - rect.width() / 2, yOri + xylinewidth + dpToPx(2) + rect.height(), xyTextPaint);
     canvas.drawRoundRect(x - xValueRect.width() / 2 - dpToPx(3), yOri + xylinewidth + dpToPx(1), x + xValueRect.width() / 2 + dpToPx(3), yOri + xylinewidth + dpToPx(2) + xValueRect.height() + dpToPx(2), dpToPx(2), dpToPx(2), xyTextPaint);
    } else {
     canvas.drawText(text, 0, text.length(), x - rect.width() / 2, yOri + xylinewidth + dpToPx(2) + rect.height(), xyTextPaint);
    }
   }
  }
 }

5、点击的处理以及左右

重写ontouchEven()方法,来处理点击和滑动

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  if (isScrolling)
   return super.onTouchEvent(event);
  this.getParent().requestDisallowInterceptTouchEvent(true);//当该view获得点击事件,就请求父控件不拦截事件
  obtainVelocityTracker(event);
  switch (event.getAction()) {
   case MotionEvent.ACTION_DOWN:
    startX = event.getX();
    break;
   case MotionEvent.ACTION_MOVE:
    if (interval * xValue.size() > width - xOri) {//当期的宽度不足以呈现全部数据
     float dis = event.getX() - startX;
     startX = event.getX();
     if (xInit + dis < minXInit) {
      xInit = minXInit;
     } else if (xInit + dis > maxXInit) {
      xInit = maxXInit;
     } else {
      xInit = xInit + dis;
     }
     invalidate();
    }
    break;
   case MotionEvent.ACTION_UP:
    clickAction(event);
    scrollAfterActionUp();
    this.getParent().requestDisallowInterceptTouchEvent(false);
    recycleVelocityTracker();
    break;
   case MotionEvent.ACTION_CANCEL:
    this.getParent().requestDisallowInterceptTouchEvent(false);
    recycleVelocityTracker();
    break;
  }
  return true;
 }

点击的处理是计算当前点击的X、Y坐标范围进行判断点击的是那个点

 /**
  * 点击X轴坐标或者折线节点
  *
  * @param event
  */
 private void clickAction(MotionEvent event) {
  int dp8 = dpToPx(8);
  float eventX = event.getX();
  float eventY = event.getY();
  for (int i = 0; i < xValue.size(); i++) {
   //节点
   float x = xInit + interval * i;
   float y = yOri - yOri * (1 - 0.1f) * value.get(xValue.get(i)) / yValue.get(yValue.size() - 1);
   if (eventX >= x - dp8 && eventX <= x + dp8 &&
     eventY >= y - dp8 && eventY <= y + dp8 && selectIndex != i + 1) {//每个节点周围8dp都是可点击区域
    selectIndex = i + 1;
    invalidate();
    return;
   }
   //X轴刻度
   String text = xValue.get(i);
   Rect rect = getTextBounds(text, xyTextPaint);
   x = xInit + interval * i;
   y = yOri + 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;
   }
  }
 }

处理滑动的原理,就是通过改变第一个点的X坐标,通过改变这个基本点,依次改变后面的X轴的点的坐标。

最后在布局里面应用就可以啦,我就不贴代码啦!

总结:

项目还是有缺点的:

(1)左右滑动时,抬起手指仍然可以快速滑动;代码里面给出了一种解决方案,但是太过于暂用资源,没有特殊要求不建议使用,所以给出一个boolean类型的自定义属性isScroll,true:启动,反之亦然;还有一种解决方案就是外面再加一层横向ScrollView,请读者自行解决,也很简单,只需要稍作修改即可。

(2)点击的时候忘记添加回调,只有添加了回调在可以在activity或者fragment里面获取点击的内容;代码很简单,自行脑补。

项目地址1
项目地址2

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

(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图表 MPAndroidChart折线图

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

  • Android HelloChart开源库图表之折线图的实例代码

    前面我们介绍了开源图表库MPAndroidChart,请参考: Android MPAndroidChart开源库图表之折线图的实例代码 我们今天介绍的将是一个更为优秀的图表库,比MPAndroidChart性能更好,功能更完善,UI风格更美观,坐标轴更精细. 支持缩放.滑动以及平移.Zoom(pinch to zoom, double tap zoom), scroll and fling 支持自定义坐标轴(比如坐标轴位置:上下左右内部),支持自动生成坐标轴.Custom and auto-g

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

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

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

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

  • 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自定义控件实现折线图

    本文实例实现一个如下图所示的Android折线图,供大家参考,具体内容如下 首先是控件绘图区域的划分,控件左边取一小部分(控件总宽度的八分之一)绘制表头,右边剩余的部分绘制表格 确定表格的行列数,首先绘制一个三行八列的网格,设置好行列的坐标后开始绘制 /*绘制三条横线*/ for(int i=0;i<3;i++){ canvas.drawLine(textWide, mLineYs[i], totalWidth, mLineYs[i], mPaintLine); } /*绘制八条竖线*/ for

  • Android绘制动态折线图

    所谓动态折线图,就是折线图能随着手指的滑动进行动态绘制,这里很定会产生动画效果.基于这个效果,这里使用SurfaceView进行制图. 实现步奏如下: (1): 这里新建一个绘图ChartView,继承SurfaceView并实现SurfaceHolder.Callback , Runnable接口,主要绘图工作在子线程中完成. (2):现实 SurfaceHolder.Callback接口的三个方法,并在 surfaceCreated中开启子线程进行绘图. (3):重写onTouchEvent

  • Android MPAndroidChart开源库图表之折线图的实例代码

    本文讲述了Android MPAndroidChart开源库图表之折线图的实例代码.分享给大家供大家参考,具体如下: 承接上一篇文章,请参考Android HelloChart开源库图表之折线图的实例代码 1. 将mpandroidchartlibrary-2-0-8.jar包copy到项目的libs中: 2. 定义xml文件. 3.  主要Java逻辑代码如下,注释已经都添加上了. package com.example.mpandroidlinechart; import java.util

  • Android自定义可左右滑动和点击的折线图

    前言 前几天有小盆友让我写一个折线图,可以点击,可以左右滑动.对于折线肯定有很多项目都使用过,所以网上肯定也有很多demo,像AndroidChart.HelloChart之类的,功能相当丰富,效果也很赞,但是太重了,其他的小demo又不符合要求,当然了,我写的自定义折线图的思想也有来自这些小demo,对他们表示感谢. 效果图 废话不多说,先上效果图: 效果是不是很赞,如果上图满足你的需求,那就继续往下看. 自定义折线图的步骤: 1.自定义view所需要的属性 确定所需要的自定义view的属性,

  • Android自定义星星可滑动评分控件

    本文实例为大家分享了Android自定义星星可滑动评分控件的具体方法,供大家参考,具体内容如下 此控件通过线性布局结合ImageView来实现. 具有展示分数,滑动评分功能,可设置0-10分,自行设置星星图片,是否可点击与滑动,星星间距. 效果如下: 需准备好下面三张图片 先看自定义属性: <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name

  • Android 自定义view模板并实现点击事件的回调

    Android 自定义view模板并实现点击事件的回调 主要的目的就是仿老版QQ的一个界面做一个模板.然后实现点击事件的回调.先看效果图: 步骤如下: 1.在res/values/目录下新建一个atts.xml文件 内容如下: <resources> <declare-styleable name="topbar"> <attr name="title" format="string"/> <attr n

  • Android自定义带增长动画和点击弹窗提示效果的柱状图DEMO

    项目中最近用到各种图表,本来打算用第三方的,例如MPAndroid,这是一个十分强大的图表库,应用起来十分方便,但是最终发现和设计不太一样,没办法,只能自己写了.今天将写好的柱状图的demo贴在这,该柱状图可根据数据的功能有一下几点: 1. 根据数据的多少,动态的绘制柱状图柱子的条数: 2. 柱状图每条柱子的绘制都有动态的动画效果: 3. 每条柱子有点击事件,点击时弹出提示框,显示相关信息,规定时间后,弹窗自动消失. 好了,先上演示图: 下边贴出相关代码: 自定义柱状图类: package co

  • Android 自定义TextView实现滑动解锁高亮文字

    下面一段代码给大家分享Android 自定义TextView实现滑动解锁高亮文字效果,具体代码如下所示: public class HightLightTextView extends TextView { // 存储view的宽度 private int mTextViewWidth = 0; // 画笔 private Paint mPaint; // 线性渲染 private LinearGradient mLinearGradient; // 存储变换的matrix private Ma

  • Android自定义实现可滑动按钮

    本文实例为大家分享了Android自定义实现可滑动按钮的具体代码,供大家参考,具体内容如下 实现逻辑 1.创建一个类继承view类,实现里面的onMeasure() onDraw()方法 2.在 onMeasure() 中需要调用setMeasuredDimension(viewWidth,viewheight),用来绘制按钮的位置区域 3.需要加载按钮的背景和滑块资源 并且转化为bitmap对象 4.获取背景图片的宽和高作为自定义控件的宽和高 5.获取滑块的宽度,用来调整按钮的开和关 6.在o

  • Android自定义view实现滑动解锁效果

    本文实例为大家分享了Android自定义view实现滑动解锁的具体代码,供大家参考,具体内容如下 1. 需求如下: 近期需要做一个类似屏幕滑动解锁的功能,右划开始,左划暂停. 2. 需求效果图如下 3. 实现效果展示 4. 自定义view如下 /** * Desc 自定义滑动解锁View * Author ZY * Mail sunnyfor98@gmail.com * Date 2021/5/17 11:52 */ @SuppressLint("ClickableViewAccessibili

  • Android自定义SeekBar实现滑动验证且不可点击

    最近公司因为短信接口被盗刷的比较严重,需要做一个类似于淘宝的滑动验证,用于特定环境,以增加一层保障.拿到需求首先想到的是自定义ViewGroup来实现,里面放一个seekbar和TextView即可.但是有更简单的方法,直接在布局中放入seekbar和TextView,不就ok了?用最简单快捷的方法实现需求,才是硬道理. 值得一提的是,seekbar默认情况下是支持点击事件的,也就是说,用户可以直接点击进度条以实现滑动验证这是不允许的,因此,自定义seekbar,屏蔽点击事件.下面我们先从see

  • android自定义ViewPager水平滑动弹性效果

    android ViewPager是一个经常要用到的组件,但android系统本身为我们提供的ViewPager是没有任何效果的,只能是一页一页的滑动,这样会让人感觉很死板,在看一些知名大公司的App时,看到了他们的ViewPager在滑动到最开始或者最后的时候是有一个弹性效果的,使用起来感觉非常的好,于是乎就是百度搜了一下,在StackOverflow中看到一篇文章就是讲如何实现这个效果的. 先看下效果图:滑动到最后一页时仍然可以拉动-- 代码如下: package com.example.m

  • Android自定义StickinessView粘性滑动效果

    design包的出现,Android界面发生了巨大变化,各种滑动配合的效果,下面我就粘性滑动中的一种进行自定义,效果图如下: 大家看到效果了,这里我是继承了LinerLayout,方便一点,若果是ViewGroup的话,也就复杂一点点.这里分为三部分: 1.head1,顶部可移动的Layout. 2.head2,固定的头部,不会滑动除屏幕外. 3.可滑动的Layout(这里只可以是ListView,不过也可以是任何可滑动的View,只要给出Head可滑动的时机即可) 本StickinessVie

随机推荐