Android控件实现水滴效果

看到ios版上QQ刷新效果像水滴,然后自己也想着去实现这样的效果,这篇文章暂时没有介绍下拉刷新的效果,只是单独用一个控件来实现这样的水滴效果。

效果图如下:

一、总体思路

1、画两个圆形,其中一个就是上面的大圆,还有一个是下面的小圆,大圆和小圆不断变小,大圆的位置保持不变,小圆的位置不断向下移动,即圆心不断下移。
2、画两边的曲线,这时候用到贝塞尔曲线去画。
3、用属性动画实现动态的效果。

二、代码实现

1、找出画曲线的几个关键点。

其实我是在第一张图的基础上,再在上面分别画两个圆,就可以得到第二张图了。关键是画出第一张图。

(1)在这里,p1,p2,p3,p4,这4个点分别对应两个圆的两边的点,即p1到p2就是圆的直径。p3和p4同理,那么就很容易确定这四个点的坐标了。

(2)然后c1和c2是分别控制p1到p3、p2到p4的曲线,是贝塞尔曲线的控制点。它们的横坐标对应的是p3,p4的横坐标(相等),纵坐标取两个圆心距离的一半。这样画出这个静态的图片就不难了。

(3)画上下两个圆进去,就会变成第二张图的效果。

2、在构造方法中调用init()初始化一些基本的变量

private void init(Context context, AttributeSet attrs) {
    drawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
        | Paint.FILTER_BITMAP_FLAG);
    paint = new Paint();
    paint.setColor(fillColor);
    // 转换为像素单位
    bigRadius = dip2px(context, bigRadius);
    smallRadius = dip2px(context, smallRadius);
    distance = dip2px(context, distance);
  }

3、在onDraw()方法中画水滴效果

要注意的是path需要重新new, 贝塞尔曲线的绘制,用到是path.quadTo这方法。具体可以看代码。

@Override
  protected void onDraw(Canvas canvas) {
    // 必须重新new,不然路径会重复,我之前就是这样
    path = new Path();
    // 把画布移到中心
    canvas.translate(width / 2, height / 2);
    // 从canvas层面去除绘制时锯齿
    canvas.setDrawFilter(drawFilter);
    // 当前的两个圆心的距离
    currentDis = distance * fraction;
    // 计算当前大圆的半径

    float bigRadius = this.bigRadius - currentDis / bigPercent;
    float smallRadius = 0;
    if (currentDis > 5) {// 距离大于5才改变小圆的半径
      smallRadius = this.smallRadius - currentDis / smallPercent;
    }
    // 大圆两边的两个点坐标
    leftX = -bigRadius;// 大圆当前的半径
    leftY = rightY = 0;
    rightX = bigRadius;// 大圆当前的半径
    // 小圆两边的两个点坐标
    leftX2 = -smallRadius;// 小圆当前的半径
    leftY2 = rightY2 = currentDis;
    rightX2 = -leftX2; // 小圆当前的半径
    // 两个控制点
    controlX1 = -smallRadius;// x坐标取小圆当前的半径大小
    controlY1 = currentDis / 2;// y坐标取两个圆距离的一半
    controlX2 = smallRadius;// x坐标取小圆当前的半径大小
    controlY2 = currentDis / 2;// y坐标取两个圆距离的一半
    path.moveTo(leftX, leftY);
    path.lineTo(rightX, rightY);
    // 用二阶贝塞尔曲线画右边的曲线,参数的第一个点是右边的一个控制点
    path.quadTo(controlX2, controlY2, rightX2, rightY2);
    path.lineTo(leftX2, leftY2);
    // 用二阶贝塞尔曲线画左边边的曲线,参数的第一个点是左边的一个控制点
    path.quadTo(controlX1, controlY1, leftX, leftY);
    // 画大圆
    canvas.drawCircle(0, 0, bigRadius, paint);
    // 画小圆
    canvas.drawCircle(0, currentDis, smallRadius, paint);
    // 画path
    canvas.drawPath(path, paint);
  }

4、用属性动画,实现动态的效果。

/*** 执行属性动画,实现水滴的效果 */
  public void perforAnim() {
    ValueAnimator valAnimator = ObjectAnimator.ofFloat(0, 1);
    valAnimator.addUpdateListener(new AnimatorUpdateListener() {

      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
        fraction = (float) animation.getAnimatedValue();
        postInvalidate();
      }

    });
    valAnimator.setDuration(duration);
    valAnimator.start();
  }

5、重写onMeasure()方法,处理wrap_content情况。

@Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    /*
     * 处理为wrap_content情况,那么它的specMode是AT_MOST模式,在这种模式下它的宽/高
     * 等于spectSize,这种情况下view的spectSize是parentSize,而parentSize是
     * 父容器目前可以使用大小,就是父容器当前剩余的空间大小, 就相当于使用match_parent一样 的效果,因此我们可以设置一个默认的值
     */
    int widthSpectMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSpectSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSpectMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSpectSize = MeasureSpec.getSize(heightMeasureSpec);
    if (widthSpectMode == MeasureSpec.AT_MOST
        && heightSpectMode == MeasureSpec.AT_MOST) {
      setMeasuredDimension(width, height);
    } else if (widthSpectMode == MeasureSpec.AT_MOST) {
      setMeasuredDimension(width, heightSpectSize);
    } else if (heightSpectMode == MeasureSpec.AT_MOST) {
      setMeasuredDimension(widthSpectSize, height);
    }
  }

6、其它的一些方法实现。

@Override
  protected void onLayout(boolean changed, int left, int top, int right,
      int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    if (changed) {
      width = right - left;
      height = bottom - top;
    }
  }
  /**
   * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
   */
  public int dip2px(Context context, float dpValue) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (dpValue * scale + 0.5f);
  }

7、字段的定义

private final int fillColor = 0xff999999;// 填充颜色
private Paint paint;
private int width = 100, height = 300;// 默认宽高
/* 两个圆心的最大距离 /
private int distance = 60;
/* 当前两个圆心的距离 /
private float currentDis = 0;
private float bigRadius = 20;// 大圆半径
private float smallRadius = 10;// 小圆半径
private float controlX1, controlX2, controlY1, controlY2;// 两个控制点的坐标
private float leftX, leftY, rightX, rightY;// 大圆两边的两个点的坐标
private float leftX2, leftY2, rightX2, rightY2; // 小圆两边的两个坐标
DrawFilter drawFilter;
Path path;
/* 由属性动画控制,范围为0-1 */
float fraction = 0;// 比例值
/* 大圆半径变化的比例 /
private final int bigPercent = 8;
/* 小圆半径变化的比例 /
private final int smallPercent = 20;
// 动画的执行时间
private long duration = 3000;

三、总结

一种动画效果,应该先分析它的静态的实现,然后添加动态的效果,这样就比较容易实现它的动画效果了。

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

(0)

相关推荐

  • Android实现支付宝蚂蚁森林水滴浮动效果

    可以有多个水滴,可以控制位置,水滴上下浮动.点击水滴产生搜集动画,水滴向树移动并逐渐消失,如图: 那么是如何实现的呢,下面我们一步步来分析: 1.定义一个继承Relativelayout 的子类作为容器放置多个水滴并在Onlayout()中设置子控件的位置 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = getChildCount(); for (

  • Android自定义带水滴的进度条样式(带渐变色效果)

    一.直接看效果 二.直接上代码 1.自定义控件部分 package com.susan.project.myapplication; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.grap

  • Android控件实现水滴效果

    看到ios版上QQ刷新效果像水滴,然后自己也想着去实现这样的效果,这篇文章暂时没有介绍下拉刷新的效果,只是单独用一个控件来实现这样的水滴效果. 效果图如下: 一.总体思路 1.画两个圆形,其中一个就是上面的大圆,还有一个是下面的小圆,大圆和小圆不断变小,大圆的位置保持不变,小圆的位置不断向下移动,即圆心不断下移. 2.画两边的曲线,这时候用到贝塞尔曲线去画. 3.用属性动画实现动态的效果. 二.代码实现 1.找出画曲线的几个关键点. 其实我是在第一张图的基础上,再在上面分别画两个圆,就可以得到第

  • Android控件之使用ListView实现时间轴效果

     实现思路: 该View是通过ListView实现的,通过实体两个字段内容content和时间time来展示每个ListItem 时间轴是使用上面一条线(20dp)和中间一个圆(15dp)和下面一条线(40dp)组装成的 在ListView中,设置其分割线为空,并且没有点击效果 效果图: 步骤一:使用xml画出一个灰色的圆点(time_cycle.xml) <?xml version="1.0" encoding="utf-8"?> <shape

  • Android自定义View控件实现刷新效果

    三种得到LinearInflater的方法 a. LayoutInflater inflater = getLayoutInflater(); b. LayoutInflater localinflater = (LayoutInflater)context.getSystemService (Context.LAYOUT_INFLATER_SERVICE); c. LayoutInflater inflater = LayoutInflater.from(context); onDraw 方法

  • Android ScrollView实现向上滑动控件顶部悬浮效果

    本文参考了: <上滑停靠顶端的悬浮框>的代码,在此表示感谢.[上滑停靠顶端的悬浮框]里的实现方法是使用两个控件,滑动时,监听ScrollView的滚动Y值,从而通过对两个控件的显示隐藏来实现控件的顶部悬浮.但是实际应用场景中,有可能需要悬浮的控件里面的内容是比较多的,如果通过显示隐藏的方式来实现的话,操作控件里的内容时,需要重复定义两套变量,对控件里的内容进行修改时也是要操作再次,非常麻烦. 本文的方法是通过addView和removeView来实现的. 一.首先让ScrollView实现滚动

  • android控件实现单击拖动效果

    本文实例为大家分享了android控件实现单击拖动效果的具体代码,供大家参考,具体内容如下 分析 setOnClickListener setOnClickListener 可以接收控件的单击动作,无返回值 要想拖动控件,就要利用 setOnTouchListener 自己定义了 setOnTouchListener 通过按下时的坐标和移动时的坐标之间的差值,来计算移动的距离,然后更改控件的位置以达到拖动的目的 因 Touch 事件执行完成后如果返回false则会继续执行单击事件,不是我们想要的

  • android控件Banner实现简单轮播图效果

    本文实例为大家分享了android控件Banner实现简单轮播图效果的具体代码,供大家参考,具体内容如下 实现这个轮播图是在Fragment里实现的,所以要想实现,首先要创建Fragment 首先是布局文件中的展示 <com.youth.banner.Banner android:id="@+id/banner" android:layout_width="match_parent" android:layout_height="500dp"

  • 很赞的引导界面效果Android控件ImageSwitcher实现

    本文实例为大家分享了Android控件ImageSwitcher实现引导界面的代码,供大家参考,具体内容如下 效果图: 布局代码: <?xml version="1.0" encoding="UTF-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent&

  • Android控件之Gallery用法实例分析

    本文实例讲述了Android控件之Gallery用法.分享给大家供大家参考.具体如下: Gallery组件主要用于横向显示图像列表,不过按常规做法.Gallery组件只能有限地显示指定的图像.也就是说,如果为Gallery组件指定了10张图像,那么当Gallery组件显示到第10张时,就不会再继续显示了.这虽然在大多数时候没有什么关系,但在某些情况下,我们希望图像显示到最后一张时再重第1张开始显示,也就是循环显示.要实现这种风格的Gallery组件,就需要对Gallery的Adapter对象进行

  • Android 控件设置阴影效果

    本文主要记录Android控件设置阴影 给控件设置阴影,会使得界面元素更好看一写,google 给我们提供了一个现成的控CardView,可以将CardView看做是FrameLayout在自身之上添加了圆角和阴影效果 本文是使用给控件设置背景实现阴影 在res/drawable 下新建一个 Drawable Resource File 使用 layer-list 图层 就是说可以多个图层一层一层盖上去 新建一个渐变的图层 item作为背景图层,主要是 gradient,shape是用来定义形状

  • Android控件系列之RadioButton与RadioGroup使用方法

    学习目的: 1.掌握在Android中如何建立RadioGroup和RadioButton 2.掌握RadioGroup的常用属性 3.理解RadioButton和CheckBox的区别 4.掌握RadioGroup选中状态变换的事件(监听器) RadioButton和CheckBox的区别: 1.单个RadioButton在选中后,通过点击无法变为未选中 单个CheckBox在选中后,通过点击可以变为未选中 2.一组RadioButton,只能同时选中一个 一组CheckBox,能同时选中多个

随机推荐