栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 移动开发 > Android

Android控件实现水滴效果

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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);
    
    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;
    }
  }
  
  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;// 默认宽高 
 
float fraction = 0;// 比例值 
/* 大圆半径变化的比例 / 
private final int bigPercent = 8; 
/* 小圆半径变化的比例 / 
private final int smallPercent = 20; 
// 动画的执行时间 
private long duration = 3000;

三、总结

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

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/155015.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号