Android Custom Swiperefreshlayout High imitation micro-letter friend Circle Drop-down Refresh _android

Source: Internet
Author: User
Tags gety

In the last article, the principle of swiperefreshlayout is simple, a general understanding of its working principle, unfamiliar can go to see: http://www.jb51.net/article/89310.htm

In the last chapter, the swiperefreshlayout of the customization is relatively poor, look at the source will find that with the style related to several classes are private and the method is written dead, only exposed a few color settings method. This makes the use of swiperefreshlayout is relatively simple, the main is to set up a listener in the Onrefresh method to complete the refresh logic. Reasonable swiperefreshlayout style is very beautiful, if you use this drop-down to refresh the style, the programmer is quiet, but this is not likely. If you want to use the official swiperefreshlayout, do not want to use Third-party controls, but also want to customize the style, what to do? Basically can only change the source code. The following is from the point of view of the revision of the source code, to customize the style of thinking.

First of all, swiperefreshlayout and internal use of the Circleimageview and materialprogressdrawable of the source code are copied out, put in a bag, easy to modify. As you can tell from the source, there are two categories in the swiperefreshlayout that are related to styles:

Circleimageview, inherit the ImageView, the source code is not pasted, mainly to draw the background, the progress Circle is drawn above, if you want to modify the position of the progress loop, you should modify the position of the Circleimageview.

Two. Materialprogressdrawable, inherited drawable implementation Animatable interface, also defines a ring class, mainly to draw the progress circle, if you want to modify the progress of the picture and animation, it should be from here.

The following is an example of the boss micro-letter of the social app, modeled after the pull of a friend's circle.

First on the effect of the picture, you can compare with the micro-letter in the phone, the overall feeling is still possible. The first time I recorded a GIF, it was too long, and some of the intermediate frames were deleted when I handled it.

This time in high imitation micro-letter, map convenient to the overall effect is also shown, readers focus on refreshing the page can be. Layout is mainly a swiperefreshlayout embedded a recyclerview, sliding to the top down drag, out of the circle is the circle of Friends of the Rainbow Circle, position on the left, and as the downward drag will continue to revolve around the center, in addition, The progress loop will not go down after it reaches a certain location. And the default effect is different Recyclerview, the default is the main layout is not followed by dragging, and micro-letter has a drag rebound effect, the background is black. After the start of the refresh, the main layout rebounded to the head, the progress circle there to turn around, refresh after the progress Circle disappeared, the whole process is this. Then take it one step at a a step.

1. Adjust the position of the progress loop
first of all to adjust the progress loop to the left, according to the view of the drawing principle, the position of the progress loop should be the parent layout that is Swiperefreshlayout OnLayout method decided to see the source code:

 @Override protected void OnLayout (Boolean changed, int left, int. top, int right, int bo
  Ttom) {Final int width = getmeasuredwidth ();
  Final int height = getmeasuredheight ();
  if (getchildcount () = = 0) {return;
  } if (mtarget = = null) {ensuretarget ();
  } if (mtarget = = null) {return;
  Final View child = Mtarget;
  Final int childleft = Getpaddingleft ();
  Final int childtop = Getpaddingtop ();
  Final int childwidth = Width-getpaddingleft ()-getpaddingright ();
  Final int childheight = Height-getpaddingtop ()-Getpaddingbottom ();
  Child.layout (Childleft, childtop, Childleft + childwidth, childtop + childheight);
  int circlewidth = Mcircleview.getmeasuredwidth ();
  int circleheight = Mcircleview.getmeasuredheight (); Mcircleview.layout ((WIDTH/2-CIRCLEWIDTH/2), Mcurrenttargetoffsettop, (WIDTH/2 + circlewidth/2), MCurrentTa
Rgetoffsettop + circleheight); }

One of the mtarget is the main layout is Recyclerview, and Mcircleview is the view of the cycle of reproduction, so the last sentence should be commented out, instead:

       Mcircleview.layout ((WIDTH/2-CIRCLEWIDTH/2), mcurrenttargetoffsettop,
//          (WIDTH/2 + CIRCLEWIDTH/2) , Mcurrenttargetoffsettop + circleheight);      Modify the X-coordinate of the progress loop so that it is located on the left
      mcircleview.layout (Childleft, Mcurrenttargetoffsettop,
          childleft+circlewidth, Mcurrenttargetoffsettop + circleheight); 

You'll be happy to see that the loop has been transferred to the left.

2. Realize drag rebound effect
next to modify the Recyclerview drag rebound effect, swiperefreshlayout the default effect is not to drag, if you want to modify is actually very simple, is to record the distance of the finger movement and let Recyclerview set the translation, then find the Ontouchevent method, modify the Action_move and action_up parts:

  Case Motionevent.action_move: {pointerindex = Motioneventcompat.findpointerindex (EV, Mactivepointerid); if (Pointerindex < 0) {LOG.E (Log_tag, "Got Action_move event but have an active invalid ID.
            ");
          return false;
Final float y = motioneventcompat.gety (ev, POINTERINDEX);
          Record the distance of the finger movement, minitialmotiony is the initial position, Drag_rate is the drag factor, the default is 0.5.
Final float overscrolltop = (y-minitialmotiony) * drag_rate;
          Assign value to top of mtarget to make drag effect mtarget.settranslationy (overscrolltop);
            if (misbeingdragged) {if (Overscrolltop > 0) {movespinner (overscrolltop);
            else {return false;
        }} break; Case MOTIONEVENT.ACTION_UP: {//When the finger is released, start the animation back to the head mtarget.animate (). Translationy (0). Setduration (

          Start (); Pointerindex = Motioneventcompat.findpointerindex (EV, MACTIvepointerid);
            if (Pointerindex < 0) {LOG.E (Log_tag, "Got action_up event but don ' t have an active pointer ID.");
          return false;
          Final float y = motioneventcompat.gety (ev, POINTERINDEX);
          Final float overscrolltop = (y-minitialmotiony) * drag_rate;
          Misbeingdragged = false;
          Finishspinner (Overscrolltop);
          Mactivepointerid = Invalid_pointer;
        return false; 

 }

Irrelevant I have skipped, the modified place I also commented, very clear. This solves the problem of drag rebound, thanks to the swiperefreshlayout framework, no need to consider the conflict, the modification is very simple.

3. Modify the icon and drag animation

The next step is the more troublesome icons and animations. It is not difficult to modify the icon, because the Circleview is inherited ImageView, it can be reflected to the circleview of the instance variable, and then SetBitmap will pass your icon. But then there is no animation, obviously it is meaningless. The reader can roughly look at the source code of the materialprogressdrawable, to achieve the default animation or more complex, I have to change the effect of micro-letter, a circle turn ah, or relatively simple, the following on the basis of the analysis of the process of the article to see how to modify.
First create a new Customprogressdrawable class, and inherit from materialprogressdrawable (need to copy the source code), also need to add the Set method Swiperefreshlayout, Facilitate the transfer of custom classes.

 public void Setprogressview (materialprogressdrawable mprogress) {
  this.mprogress = mprogress;
  Mcircleview.setimagedrawable (mprogress);
}

To draw a custom icon in customprogressdrawable, you need to expose a SetBitmap method to draw. The previous article mentions that when a finger moves, it calls the Movespinner method and passes the distance of the movement, and the method begins with a bunch of mathematical processing to get a rotation and then into the mprogress setprogressrotation, That is to say, the Setprogressrotation method is to turn the circle through the angle of passing in. The effect of the circle of friends is always to turn the center, so it is easy to rewrite:

 private float rotation;
  Private Bitmap Mbitmap;


  public void SetBitmap (Bitmap mbitmap) {
    this.mbitmap = Mbitmap;
  }


  @Override public
  void setprogressrotation (float rotation) {
//    minus sign is to be consistent with the micro-letter, turn clockwise when the pull is counterclockwise when loading, The rotational factor is to adjust the speed of the rotation.
    this.rotation =-rotation*rotation_factor;
    Invalidateself ();
  }


  @Override public
  void Draw (Canvas c) {
    Rect bound = getbounds ();
    C.rotate (Rotation,bound.exactcenterx (), Bound.exactcentery ());
    Rect src = new Rect (0,0,mbitmap.getwidth (), Mbitmap.getheight ());
    C.drawbitmap (Mbitmap,src,bound,paint);
  } 

is to constantly rotate canvas and then draw bitmap. You'll be glad to see that the circle is spinning when you pull down.

4. Set the progress loop drop-down bounds and implement the animation
when you are refreshing at this time the circle is not going to turn, and the circle by default is to drag with the fingers, there is no limit, and the effect of the circle of Friends is a circle in the bottom of a position will not continue to pull down, First to solve the problem of the drop position.
  In the Movespinner method, after calling the Setprogressrotation method to rotate, the settargetoffsettopandbottom is invoked to change the mprogress position, and the code is not posted. Now that we're going to qualify for the drop down, it should be restricted here, and the next time you move to the refresh position, the code is no longer moving, as follows:

 private void Movespinner (float overscrolltop) {
...      Settargetoffsettopandbottom (Targety-mcurrenttargetoffsettop, True/* requires update * *);      the final flush position
      int endtarget;
      if (!musingcustomstart) {
///        not modified using the default value
        endtarget = (int) (Mspinnerfinaloffset-math.abs ( Moriginaloffsettop));
      } else {
//        otherwise use the defined value
        endtarget = (int) mspinnerfinaloffset;
      }
      if (targety>=endtarget) {
//        down position is not moved down after the final position, the first parameter is offset
        settargetoffsettopandbottom (0, True/* Requires update */);
      } else{
//        otherwise continue to move down
        settargetoffsettopandbottom (Targety-mcurrenttargetoffsettop, True/* requires Update */);
      }

Here first calculate a endtarget, is the final position, the other notes of the more detailed do not say, so as to limit the position of the move down.
The next step is to keep the loop moving while the refresh occurs, so you need to know where to perform the animation when you refresh. As mentioned in the previous article, the animation of the circle is in the Mprogress start method, to see the source code:

 @Override public
void Start () {
  manimation.reset ();
  Mring.storeoriginals ();
  Already showing some the ring
  if (Mring.getendtrim ()!= Mring.getstarttrim ()) {
    mfinishing = true;
    Manimation.setduration (ANIMATION_DURATION/2);
The animation of the loop is passed into the
    mparent.startanimation (manimation);
  } else {
    mring.setcolorindex (0);
    Mring.resetoriginals ();
    Manimation.setduration (animation_duration);
The animation of the loop is passed into
    mparent.startanimation (manimation);
  }

The main thing is actually the last sentence, will turn the animation into the circle, manimation is the default rotation animation, interested can go to see for themselves, we just need to customize the animation of the circle and the introduction of the method can be. With just the Setprogressrotation method, just define an animation and constantly change the value of rotation and execute this method, the code is as follows:

 private void Setupanimation () {
//    init rotation animation
    manimation = new Animation () {
      @Override
      protected void Applytransformation (float interpolatedtime, transformation t) {
        setprogressrotation (-interpolatedtime);
      }
    ;
    manimation.setduration (5000);    Infinite repetitive
    manimation.setrepeatcount (animation.infinite);
    Manimation.setrepeatmode (Animation.restart);    uniform rotational speed
    manimation.setinterpolator (new Linearinterpolator ());
  }


  @Override public
  void Start () {
    mparent.startanimation (manimation);
  } 

That's OK!

5. Modify the completed loaded animation
now basically done, and finally an end to the animation, the default is scale animation, while the micro-letter is moving up to disappear, the final animation is done through the implementation of Swiperefreshlayout Startscaledownanimation method, To define a scale animation inside the method, we just need to comment out and define an animation for ourselves:

 private void Startscaledownanimation (Animation.animationlistener listener) {
//      mscaledownanimation = new Animation () {
//        @Override
//Public        void applytransformation (float interpolatedtime, Transformation T) {
//          setanimationprogress (1-interpolatedtime);
//        }
//      };      The final offset is the height of the final
      int deltay =-mcircleview.getbottom () at the top of the mcircleview distance;
      Mscaledownanimation = new Translateanimation (0,0,0,deltay);      mscaledownanimation.setduration (scale_down_duration);
      Mscaledownanimation.setduration ();
      Mcircleview.setanimationlistener (listener);
      Mcircleview.clearanimation ();
      Mcircleview.startanimation (mscaledownanimation);
    }

Which is an offset animation ~
With some settings in the activity, you can get an initial effect by passing in the icon of the Circle of Friends:

 Customprogressdrawable drawable = new customprogressdrawable (this,mrefreshlayout);
  Bitmap Bitmap = Bitmapfactory.decoderesource (Getresources (), R.drawable.moments_refresh_icon);
  Drawable.setbitmap (bitmap);
  Mrefreshlayout.setprogressview (drawable);
  Mrefreshlayout.setbackgroundcolor (Color.Black);
  Mrefreshlayout.setprogressbackgroundcolorschemecolor (Color.Black); Mrefreshlayout.setonrefreshlistener (New Customswiperefreshlayout.onrefreshlistener () {@Override public void OnRefr
          Esh () {final Handler Handler = new Handler () {@Override public void Handlemessage (msg) {
            Super.handlemessage (msg);
        Mrefreshlayout.setrefreshing (FALSE);
      }
      };
            New Thread (New Runnable () {@Override public void run () {try {/////////////////////////
          Thread.Sleep (3000);
          catch (Interruptedexception e) {e.printstacktrace (); } handler.sendemptymessage (0);
    }). Start (); }
  });

The above basic through the revision of the source code of the swiperefreshlayout to imitate the friend Circle of the Drop-down refresh effect. From the source can be seen Swiperefreshlayout is really written more closed, do not modify the source code is basically unable to customize the style, but this followed the source code over the idea is more clear. Later, if you have the opportunity to try to encapsulate it again ~

Finally, attach the complete code of customprogressdrawable. Swiperefreshlayout is too long to send out, the change of place should be mentioned.

public class Customprogressdrawable extends materialprogressdrawable{//rotation factor, adjusting rotation speed private static final int rotatio
N_factor = 5*360;
  When loading the animation private Animation manimation;
  Private View mparent;
Private Bitmap Mbitmap;
  Rotary angle private float rotation;


  Private Paint Paint;
    Public customprogressdrawable (context, View parent) {Super (context, parent);
    Mparent = parent;
    Paint = new paint ();
  Setupanimation (); } private void Setupanimation () {//init rotation animation manimation = new Animation () {@Override protected void
      Applytransformation (float interpolatedtime, transformation t) {setprogressrotation (-interpolatedtime);
    }
    };
Manimation.setduration (5000);
    Infinite repetitive manimation.setrepeatcount (animation.infinite);
Manimation.setrepeatmode (Animation.restart);
  Uniform rotational speed Manimation.setinterpolator (new Linearinterpolator ()); @Override public void Start () {mparent.startanimation (manimation);
  public void SetBitmap (Bitmap mbitmap) {this.mbitmap = Mbitmap;
    @Override public void setprogressrotation (float rotation) {//minus sign is intended to be consistent with the micro-letter, clockwise when the drop is turned counterclockwise, rotation factor is to adjust the speed of the transfer.
    This.rotation =-rotation*rotation_factor;
  Invalidateself ();
    @Override public void Draw (Canvas c) {Rect bound = getbounds ();
    C.rotate (Rotation,bound.exactcenterx (), Bound.exactcentery ());
    Rect src = new Rect (0,0,mbitmap.getwidth (), Mbitmap.getheight ());
  C.drawbitmap (Mbitmap,src,bound,paint);
 }
}

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.