当前位置: 移动技术网 > 移动技术>移动开发>Android > 超好看的下拉刷新动画Android代码实现

超好看的下拉刷新动画Android代码实现

2019年07月24日  | 移动技术网移动技术  | 我要评论

最近看到了好多高端、大气、上档次的动画效果,如果给你的项目中加上这些动画,相信你的app一定很优秀,今天给大家分析一下来自yalantis的一个超好看的下拉刷新动画。

首先我们看一下效果如何:

怎么样?是不是很高大上?接下来我们看一下代码:

一、首先我们需要自定义刷新的动态refreshview(也就是下拉时候的头)
1.初始化头所占用的dimens

private void initiatedimens() { 
    mscreenwidth = mcontext.getresources().getdisplaymetrics().widthpixels; 
    mjettopoffset = mparent.gettotaldragdistance() * 0.5f; 
    mtop = -mparent.gettotaldragdistance(); 
  } 

2.为头填充图片,设置图片的大小
分别为左边的云彩,右边的云彩,中间的云彩还有中间的飞机,飞机是带有动画的,下面会介绍飞机的动画

private void createbitmaps() { 
    mleftclouds = bitmapfactory.decoderesource(mcontext.getresources(), r.drawable.clouds_left); 
    mrightclouds = bitmapfactory.decoderesource(mcontext.getresources(), r.drawable.clouds_right); 
    mfrontclouds = bitmapfactory.decoderesource(mcontext.getresources(), r.drawable.clouds_center); 
    mjet = bitmapfactory.decoderesource(mcontext.getresources(), r.drawable.airplane); 
 
    mjetwidthcenter = mjet.getwidth() / 2; 
    mjetheightcenter = mjet.getheight() / 2; 
    mfrontcloudwidthcenter = mfrontclouds.getwidth() / 2; 
    mfrontcloudheightcenter = mfrontclouds.getheight() / 2; 
 
    mrightcloudswidthcenter = mrightclouds.getwidth() / 2; 
    mrightcloudsheightcenter = mrightclouds.getheight() / 2; 
    mleftcloudswidthcenter = mleftclouds.getwidth() / 2; 
    mleftcloudsheightcenter = mleftclouds.getheight() / 2; 
  } 

3.然后我们来画这个头

public void draw(@nonnull canvas canvas) { 
    final int savecount = canvas.save(); 
 
    // draw background. 
    canvas.drawcolor(mcontext.getresources().getcolor(r.color.sky_background)); 
 
    if (isrefreshing) { 
      // set up new set of wind 
      while (mwinds.size() < wind_set_amount) { 
        float y = (float) (mparent.gettotaldragdistance() / (math.random() * random_y_coefficient)); 
        float x = random(min_wind_x_offset, max_wind_x_offset); 
 
        // magic with checking interval between winds 
        if (mwinds.size() > 1) { 
          y = 0; 
          while (y == 0) { 
            float tmp = (float) (mparent.gettotaldragdistance() / (math.random() * random_y_coefficient)); 
 
            for (map.entry<float, float> wind : mwinds.entryset()) { 
              // we want that interval will be greater than fifth part of draggable distance 
              if (math.abs(wind.getkey() - tmp) > mparent.gettotaldragdistance() / random_y_coefficient) { 
                y = tmp; 
              } else { 
                y = 0; 
                break; 
              } 
            } 
          } 
        } 
 
        mwinds.put(y, x); 
        drawwind(canvas, y, x); 
      } 
 
      // draw current set of wind 
      if (mwinds.size() >= wind_set_amount) { 
        for (map.entry<float, float> wind : mwinds.entryset()) { 
          drawwind(canvas, wind.getkey(), wind.getvalue()); 
        } 
      } 
 
      // we should to create new set of winds 
      if (minversedirection && mnewwindset) { 
        mwinds.clear(); 
        mnewwindset = false; 
        mwindlinewidth = random(min_wind_line_width, max_wind_line_width); 
      } 
 
      // needed for checking direction 
      mlastanimationtime = mloadinganimationtime; 
    } 
 
    drawjet(canvas); 
    drawsideclouds(canvas); 
    drawcenterclouds(canvas); 
 
    canvas.restoretocount(savecount); 
  } 
/** 
   * draw wind on loading animation 
   * 
   * @param canvas - area where we will draw 
   * @param y    - y position fot one of lines 
   * @param xoffset - x offset for on of lines 
   */ 
  private void drawwind(canvas canvas, float y, float xoffset) { 
    /* we should multiply current animation time with this coefficient for taking all screen width in time 
    removing slowing of animation with dividing on {@link #slow_down_animation_coefficient} 
    and we should don't forget about distance that should "fly" line that depend on screen of device and x offset 
    */ 
    float cof = (mscreenwidth + xoffset) / (loading_animation_coefficient / slow_down_animation_coefficient); 
    float time = mloadinganimationtime; 
 
    // horrible hack for revers animation that should work like restart animation 
    if (mlastanimationtime - mloadinganimationtime > 0) { 
      minversedirection = true; 
      // take time from 0 to end of animation time 
      time = (loading_animation_coefficient / slow_down_animation_coefficient) - mloadinganimationtime; 
    } else { 
      mnewwindset = true; 
      minversedirection = false; 
    } 
 
    // taking current x position of drawing wind 
    // for fully disappearing of line we should subtract wind line width 
    float x = (mscreenwidth - (time * cof)) + xoffset - mwindlinewidth; 
    float xend = x + mwindlinewidth; 
 
    canvas.drawline(x, y, xend, y, mwindpaint); 
  } 
 
  private void drawsideclouds(canvas canvas) { 
    matrix matrixleftclouds = mmatrix; 
    matrix matrixrightclouds = madditionalmatrix; 
    matrixleftclouds.reset(); 
    matrixrightclouds.reset(); 
 
    // drag percent will newer get more then 1 here 
    float dragpercent = math.min(1f, math.abs(mpercent)); 
 
    boolean overdrag = false; 
 
    // but we check here for overdrag 
    if (mpercent > 1.0f) { 
      overdrag = true; 
    } 
 
    float scale; 
    float scalepercentdelta = dragpercent - scale_start_percent; 
    if (scalepercentdelta > 0) { 
      float scalepercent = scalepercentdelta / (1.0f - scale_start_percent); 
      scale = side_clouds_initial_scale + (side_clouds_final_scale - side_clouds_initial_scale) * scalepercent; 
    } else { 
      scale = side_clouds_initial_scale; 
    } 
 
    // current y position of clouds 
    float dragyoffset = mparent.gettotaldragdistance() * (1.0f - dragpercent); 
 
    // position where clouds fully visible on screen and we should drag them with content of listview 
    int cloudsvisibleposition = mparent.gettotaldragdistance() / 2 - mleftcloudsheightcenter; 
 
    boolean needmovecloudswithcontent = false; 
    if (dragyoffset < cloudsvisibleposition) { 
      needmovecloudswithcontent = true; 
    } 
 
    float offsetrightx = mscreenwidth - mrightclouds.getwidth(); 
    float offsetrighty = (needmovecloudswithcontent 
        ? mparent.gettotaldragdistance() * dragpercent - mleftclouds.getheight() 
        : dragyoffset) 
        + (overdrag ? mtop : 0); 
 
    float offsetleftx = 0; 
    float offsetlefty = (needmovecloudswithcontent 
        ? mparent.gettotaldragdistance() * dragpercent - mleftclouds.getheight() 
        : dragyoffset) 
        + (overdrag ? mtop : 0); 
 
    // magic with animation on loading process 
    if (isrefreshing) { 
      if (checkcurrentanimationpart(animationpart.first)) { 
        offsetlefty += getanimationpartvalue(animationpart.first) / y_side_clouds_slow_down_cof; 
        offsetrightx -= getanimationpartvalue(animationpart.first) / x_side_clouds_slow_down_cof; 
      } else if (checkcurrentanimationpart(animationpart.second)) { 
        offsetlefty += getanimationpartvalue(animationpart.second) / y_side_clouds_slow_down_cof; 
        offsetrightx -= getanimationpartvalue(animationpart.second) / x_side_clouds_slow_down_cof; 
      } else if (checkcurrentanimationpart(animationpart.third)) { 
        offsetlefty -= getanimationpartvalue(animationpart.third) / y_side_clouds_slow_down_cof; 
        offsetrightx += getanimationpartvalue(animationpart.third) / x_side_clouds_slow_down_cof; 
      } else if (checkcurrentanimationpart(animationpart.fourth)) { 
        offsetlefty -= getanimationpartvalue(animationpart.fourth) / x_side_clouds_slow_down_cof; 
        offsetrightx += getanimationpartvalue(animationpart.fourth) / y_side_clouds_slow_down_cof; 
      } 
    } 
 
    matrixrightclouds.postscale(scale, scale, mrightcloudswidthcenter, mrightcloudsheightcenter); 
    matrixrightclouds.posttranslate(offsetrightx, offsetrighty); 
 
    matrixleftclouds.postscale(scale, scale, mleftcloudswidthcenter, mleftcloudsheightcenter); 
    matrixleftclouds.posttranslate(offsetleftx, offsetlefty); 
 
    canvas.drawbitmap(mleftclouds, matrixleftclouds, null); 
    canvas.drawbitmap(mrightclouds, matrixrightclouds, null); 
  } 
 
  private void drawcenterclouds(canvas canvas) { 
    matrix matrix = mmatrix; 
    matrix.reset(); 
    float dragpercent = math.min(1f, math.abs(mpercent)); 
 
    float scale; 
    float overdragpercent = 0; 
    boolean overdrag = false; 
 
    if (mpercent > 1.0f) { 
      overdrag = true; 
      // here we want know about how mach percent of over drag we done 
      overdragpercent = math.abs(1.0f - mpercent); 
    } 
 
    float scalepercentdelta = dragpercent - scale_start_percent; 
    if (scalepercentdelta > 0) { 
      float scalepercent = scalepercentdelta / (1.0f - scale_start_percent); 
      scale = center_clouds_initial_scale + (center_clouds_final_scale - center_clouds_initial_scale) * scalepercent; 
    } else { 
      scale = center_clouds_initial_scale; 
    } 
 
    float parallaxpercent = 0; 
    boolean parallax = false; 
    // current y position of clouds 
    float dragyoffset = mparent.gettotaldragdistance() * dragpercent; 
    // position when should start parallax scrolling 
    int startparallaxheight = mparent.gettotaldragdistance() - mfrontcloudheightcenter; 
 
    if (dragyoffset > startparallaxheight) { 
      parallax = true; 
      parallaxpercent = dragyoffset - startparallaxheight; 
    } 
 
    float offsetx = (mscreenwidth / 2) - mfrontcloudwidthcenter; 
    float offsety = dragyoffset 
        - (parallax ? mfrontcloudheightcenter + parallaxpercent : mfrontcloudheightcenter) 
        + (overdrag ? mtop : 0); 
 
    float sx = overdrag ? scale + overdragpercent / 4 : scale; 
    float sy = overdrag ? scale + overdragpercent / 2 : scale; 
 
    if (isrefreshing && !overdrag) { 
      if (checkcurrentanimationpart(animationpart.first)) { 
        sx = scale - (getanimationpartvalue(animationpart.first) / loading_animation_coefficient) / 8; 
      } else if (checkcurrentanimationpart(animationpart.second)) { 
        sx = scale - (getanimationpartvalue(animationpart.second) / loading_animation_coefficient) / 8; 
      } else if (checkcurrentanimationpart(animationpart.third)) { 
        sx = scale + (getanimationpartvalue(animationpart.third) / loading_animation_coefficient) / 6; 
      } else if (checkcurrentanimationpart(animationpart.fourth)) { 
        sx = scale + (getanimationpartvalue(animationpart.fourth) / loading_animation_coefficient) / 6; 
      } 
      sy = sx; 
    } 
 
    matrix.postscale(sx, sy, mfrontcloudwidthcenter, mfrontcloudheightcenter); 
    matrix.posttranslate(offsetx, offsety); 
 
    canvas.drawbitmap(mfrontclouds, matrix, null); 
  } 
 
  private void drawjet(canvas canvas) { 
    matrix matrix = mmatrix; 
    matrix.reset(); 
 
    float dragpercent = mpercent; 
    float rotateangle = 0; 
 
    // check overdrag 
    if (dragpercent > 1.0f && !mendofrefreshing) { 
      rotateangle = (dragpercent % 1) * 10; 
      dragpercent = 1.0f; 
    } 
 
    float offsetx = ((mscreenwidth * dragpercent) / 2) - mjetwidthcenter; 
 
    float offsety = mjettopoffset 
        + (mparent.gettotaldragdistance() / 2) 
        * (1.0f - dragpercent) 
        - mjetheightcenter; 
 
    if (isrefreshing) { 
      if (checkcurrentanimationpart(animationpart.first)) { 
        offsety -= getanimationpartvalue(animationpart.first); 
      } else if (checkcurrentanimationpart(animationpart.second)) { 
        offsety -= getanimationpartvalue(animationpart.second); 
      } else if (checkcurrentanimationpart(animationpart.third)) { 
        offsety += getanimationpartvalue(animationpart.third); 
      } else if (checkcurrentanimationpart(animationpart.fourth)) { 
        offsety += getanimationpartvalue(animationpart.fourth); 
      } 
    } 
 
    matrix.settranslate(offsetx, offsety); 
 
    if (dragpercent == 1.0f) { 
      matrix.prerotate(rotateangle, mjetwidthcenter, mjetheightcenter); 
    } 
 
    canvas.drawbitmap(mjet, matrix, null); 
  } 

动画效果已经画好了,下面我们来看看怎么结合下拉刷新来调用吧?
二、我们还需要自定义一个pulltorefreshview(下拉刷新)
1.我们的pulltorefreshview这里需要继承viewgroup
我们先把刚才定义的刷新时的动画加进来

private refreshview mrefreshview; 
<pre name="code" class="java">private imageview mrefreshimageview; 
<pre name="code" class="java">mrefreshimageview = new imageview(context); 
    mrefreshview = new refreshview(getcontext(), this); 
    mrefreshimageview.setimagedrawable(mrefreshview); 
 
    addview(mrefreshimageview); 

2.然后我们设置ontouchevent()事件

@override 
  public boolean ontouchevent(@nonnull motionevent ev) { 
 
    if (!misbeingdragged) { 
      return super.ontouchevent(ev); 
    } 
 
    final int action = motioneventcompat.getactionmasked(ev); 
 
    switch (action) { 
      case motionevent.action_move: { 
        final int pointerindex = motioneventcompat.findpointerindex(ev, mactivepointerid); 
        if (pointerindex < 0) { 
          return false; 
        } 
 
        final float y = motioneventcompat.gety(ev, pointerindex); 
        final float ydiff = y - minitialmotiony; 
        final float scrolltop = ydiff * drag_rate; 
        mcurrentdragpercent = scrolltop / mtotaldragdistance; 
        if (mcurrentdragpercent < 0) { 
          return false; 
        } 
        float boundeddragpercent = math.min(1f, math.abs(mcurrentdragpercent)); 
        float extraos = math.abs(scrolltop) - mtotaldragdistance; 
        float slingshotdist = mtotaldragdistance; 
        float tensionslingshotpercent = math.max(0, 
            math.min(extraos, slingshotdist * 2) / slingshotdist); 
        float tensionpercent = (float) ((tensionslingshotpercent / 4) - math.pow( 
            (tensionslingshotpercent / 4), 2)) * 2f; 
        float extramove = (slingshotdist) * tensionpercent / 2; 
        int targety = (int) ((slingshotdist * boundeddragpercent) + extramove); 
 
        mrefreshview.setpercent(mcurrentdragpercent); 
        settargetoffsettop(targety - mcurrentoffsettop, true); 
        break; 
      } 
      case motioneventcompat.action_pointer_down: 
        final int index = motioneventcompat.getactionindex(ev); 
        mactivepointerid = motioneventcompat.getpointerid(ev, index); 
        break; 
      case motioneventcompat.action_pointer_up: 
        onsecondarypointerup(ev); 
        break; 
      case motionevent.action_up: 
      case motionevent.action_cancel: { 
        if (mactivepointerid == invalid_pointer) { 
          return false; 
        } 
        final int pointerindex = motioneventcompat.findpointerindex(ev, mactivepointerid); 
        final float y = motioneventcompat.gety(ev, pointerindex); 
        final float overscrolltop = (y - minitialmotiony) * drag_rate; 
        misbeingdragged = false; 
        if (overscrolltop > mtotaldragdistance) { 
          setrefreshing(true, true); 
        } else { 
          mrefreshing = false; 
          animateoffsettoposition(manimatetostartposition); 
        } 
        mactivepointerid = invalid_pointer; 
        return false; 
      } 
    } 
 
    return true; 
  } 

三、最后我们看怎样在activity中使用这个下拉刷新控件
1.先看一下布局文件
这里是我们的下拉刷新空间嵌套着我们的listview,然后我们再给listview填充数据即可

<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="match_parent" 
  tools:context=".pulltorefreshactivity"> 
 
  <com.hankkin.animationpulltorefreshdemo.pulltorefreshview 
    android:id="@+id/pull_to_refresh" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 
 
    <listview 
      android:id="@+id/list_view" 
      android:divider="@null" 
      android:dividerheight="0dp" 
      android:fadingedge="none" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" /> 
 
  </com.hankkin.animationpulltorefreshdemo.pulltorefreshview> 
 
</relativelayout> 

2.为listview填充数据
为了我们的效果比较好看,这里我们给listview的每一个item填充不同的颜色,看起来会比较高大上。

map<string, integer> map; 
    list<map<string, integer>> samplelist = new arraylist<map<string, integer>>(); 
 
 
    int[] colors = { 
        r.color.saffron, 
        r.color.eggplant, 
        r.color.sienna}; 
 
    int[] tripnames = { 
        r.string.trip_to_india, 
        r.string.trip_to_italy, 
        r.string.trip_to_indonesia}; 
 
    for (int i = 0; i < tripnames.length; i++) { 
      map = new hashmap<string, integer>(); 
      map.put(sampleadapter.key_name, tripnames[i]); 
      map.put(sampleadapter.key_color, colors[i]); 
      samplelist.add(map); 
    } 
 
    listview listview = (listview) findviewbyid(r.id.list_view); 
    listview.setadapter(new sampleadapter(this, r.layout.list_item, samplelist)); 

3.最后,我们再设置一下下拉刷新的监听事件就ok了

mpulltorefreshview = (pulltorefreshview) findviewbyid(r.id.pull_to_refresh); 
    mpulltorefreshview.setonrefreshlistener(new pulltorefreshview.onrefreshlistener() { 
      @override 
      public void onrefresh() { 
        mpulltorefreshview.postdelayed(new runnable() { 
          @override 
          public void run() { 
            mpulltorefreshview.setrefreshing(false); 
          } 
        }, refresh_delay); 
      } 
    }); 

怎么样?有没有很高大上啊?

大家可以动手实践一下,希望对大家的学习有所帮助。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网