Android控件实现水滴效果

 公司新闻     |      2019-07-31 09:54

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

效果图如下:

一、总体思路

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



二、代码实现

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

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

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

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

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

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

凯发k8国际下载private void init {
 drawfilter = new paintflagsdrawfilter;
 paint = new paint;
 paint.setcolor;
 // 转换为像素单位
 bigradius = dip2px;
 smallradius = dip2px;
 distance = dip2px;

3、在ondraw方法中画水滴效果

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

@override
 protected void ondraw {
 // 必须重新new,不然路径会重复,我之前就是这样
 path = new path;
 // 把画布移到中心
 canvas.translate;
 // 从canvas层面去除绘制时锯齿
 canvas.setdrawfilter;
 // 当前的两个圆心的距离
 currentdis = distance * fraction;
 // 计算当前大圆的半径
 float bigradius = this.bigradius - currentdis / bigpercent;
 float smallradius = 0;
 if  {// 距离大于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;
 path.lineto;
 // 用二阶贝塞尔曲线画右边的曲线,参数的第一个点是右边的一个控制点
 path.quadto;
 path.lineto;
 // 用二阶贝塞尔曲线画左边边的曲线,参数的第一个点是左边的一个控制点
 path.quadto;
 // 画大圆
 canvas.drawcircle;
 // 画小圆
 canvas.drawcircle;
 // 画path
 canvas.drawpath;

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

/*** 执行属性动画,实现水滴的效果 */
 public void perforanim {
 valueanimator valanimator = objectanimator.offloat;
 valanimator.addupdatelistener {
 @override
 public void onanimationupdate {
 fraction =  animation.getanimatedvalue;
 postinvalidate;
 valanimator.setduration;
 valanimator.start;

5、重写onmeasure方法,处理wrap_content情况。

@override
 protected void onmeasure {
 super.onmeasure;
 * 处理为wrap_content情况,那么它的specmode是at_most模式,在这种模式下它的宽/高
 * 等于spectsize,这种情况下view的spectsize是parentsize,而parentsize是
 * 父容器目前可以使用大小,就是父容器当前剩余的空间大小, 就相当于使用match_parent一样 的效果,因此我们可以设置一个默认的值
 int widthspectmode = measurespec.getmode;
 int widthspectsize = measurespec.getsize;
 int heightspectmode = measurespec.getmode;
 int heightspectsize = measurespec.getsize;
 if  {
 setmeasureddimension;
 } else if  {
 setmeasureddimension;
 } else if  {
 setmeasureddimension;
 }

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

@override
 protected void onlayout {
 super.onlayout;
 if  {
 width = right - left;
 height = bottom - top;
 * 根据手机的分辨率从 dp 的单位 转成为 px
 public int dip2px {
 final float scale = context.getresources.getdisplaymetrics.density;
 return  ;
 }

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;

三、总结

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

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