English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Using Ultra in Android-Custom Code for PullToRefresh to Implement Pull-Down Refresh

refresh in Ultra-Pull-To-Refresh has always been my favorite, here I customize a style for HeaderView. It is slightly different from the ordinary style. First, let's see the effect diagram

At a glance, it looks no different from the ordinary pull-to-refresh style, but upon closer inspection, you will find that the header is covering the content when pulling down (for simplicity, the entire layout content is just one image). The default layout style of PtrFrameLayout is to place the header above the content and display it from top to bottom gradually. To achieve the effect of the header covering the screen content, we need to find another way.

Scheme1:Modify the library files, place the display position of headerView above the content. Since PtrFrameLayout itself is a ViewGroup, modifying the onLayout code in it can achieve this style

However, considering that the modification of the Layout may cause a series of problems with the original pull-to-refresh function, I still decide to give up directly.

Scheme2:Without modifying the library files, the position of HeaderView remains unchanged, but the content of headerView is displayed above the content. In this way, the content displayed by HeaderView exceeds its own boundary. I heard that adding a magical code in the layout can achieve this, so I tried it myself and it really works. So I chose the scheme2Continue to study.

<in.srain.cube.views.ptr.PtrFrameLayout xmlns:android="http://schemas.android.com/apk/res/android 
  android:id="@"+id/ptr_layout_activity" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  android:clipChildren="false"> 

Determine the plan2The remaining steps are similar to those of a normal custom header. Create a custom View to implement the PtrUIHandler callback. The several images used include

Firstly, observe the pull-to-refresh process to know the several states in the whole process of pull-to-refresh.

Status1: When pulling down, the bottom arc is displayed, the yellow figure's eyes are closed (left1image), at this time the height pulled down is not enough to trigger the refresh operation;

Status2: After pulling down to a height that can trigger the refresh operation, the eyes open (left2image);

Status3: The action during the refresh process after releasing, the action is determined by the following5Switch to display the image carousel.

The distance of pull-to-refresh and status judgment processing is in the onUIPositionChange callback method

@Override 
  public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, PtrIndicator ptrIndicator) { 
    //The distance pulled down 
    posY = ptrIndicator.getCurrentPosY(); 
    if (!isRefresh) { 
      if (isComplete) { 
        //Just completed the pull-to-refresh operation, not yet reset the event. Use the image2.Maintain the top and bottom margins, the bottom arc does not display when pulled up or pushed down 
        drawable = ResourcesUtils.getDrawable(R.drawable.home_loading_1); 
        flag = 4; 
      } 
        //Pulling down without triggering a refresh 
        if (posY < turning) { 
          //Use the image1 
          drawable = ResourcesUtils.getDrawable(R.drawable.home_loading_0); 
          flag = 0; 
        } else if (posY < measureHeight * RATIO_TO_REFRESH) { 
          //Use the image1 
          //Display the arc below 
          drawable = ResourcesUtils.getDrawable(R.drawable.home_loading_0); 
          flag = 1; 
        } 
          //The distance pulled down has reached the position that can trigger a pull-to-refresh. Use the image2 
          drawable = ResourcesUtils.getDrawable(R.drawable.home_loading_1); 
          flag = 2; 
        } 
      } 
    } 
      //At the moment of pulling down to refresh, manually sliding the image does not change. 
      flag = 3; 
      if (!animation.isHasStart()) { 
        startAnimation(animation); 
        animation.setHasStart(true); 
      } 
    } 
    invalidate(); 
  } 

Because you can continue to slide during the waiting for refresh process, in order to ensure the normal display of the refresh, here is the judgment of isRefresh (whether it is refreshing) and isComplete (whether the refresh is completed). In addition, since the last refresh keeps displaying the later5picture, so the measureHeight of the control needs to be related to the size of the picture later, but the upper and lower margins of the small yellow man in the later picture are too small, which looks not very good visually. Therefore, when setting measureHeight, the upper and lower margins are increased specially

Drawable animationDrawable = ResourcesUtils.getDrawable(R.drawable.home_loading_2); 
measureHeight = padding * 2 + animationDrawable.getIntrinsicHeight(); 

Preparation is ready, and the focus is on the method in onDraw next. Draw according to different states, but there is a problem here, above7In the picture, the size of the small yellow man is the same, but after5There are clouds around the picture, and the overall size of the picture is larger than the first two, so extra attention needs to be paid to the drawing range of the picture during state switching.

1. Draw the arc stage, flag=1and2

switch (flag) { 
      case 1: 
      case 2: 
        controlY = (int) ((posY - turning) * RATIO_TO_REFRESH) > dragDistance * 2 
            ? dragDistance * 2 + measureHeight : (int) ((posY - turning) * RATIO_TO_REFRESH) 
            + measureHeight; 
        //Pull down arc 
        mPath.reset(); 
        mPath.moveTo(0, measureHeight); 
        mPath.quadTo(getWidth(), / 2, controlY, getWidth(), measureHeight); 
        mPath.lineTo(getWidth(), 0); 
        mPath.lineTo(0, 0); 
        mPath.close(); 
        mDrawableRect.set((getWidth() - drawable.getIntrinsicWidth()) / 2, 
            getBsrPositionY(controlY) - drawable.getIntrinsicHeight() * 2 / 3, 
            (canvas.getWidth(), + drawable.getIntrinsicWidth()) / 2, 
            getBsrPositionY(controlY) + drawable.getIntrinsicHeight() / 3); 
        //Draw the arc 
        mPaint.setXfermode(null); 
        canvas.drawPath(mPath, mPaint); 
        canvas.save(); 
        canvas.clipPath(mPath); 
        drawable.setBounds(mDrawableRect); 
        drawable.draw(canvas); 
        canvas.restore(); 
        break; 

Among which the arc is a second-order Bezier curve.

In the code, controlY is the control point P1has the Y coordinate, the turning value indicates the distance to pull down before starting to draw the arc (you can modify the value to see the effect). Here, our control point X coordinate is at the center of the screen (t=0.5),P0 and P2The X coordinate is also determined, and you only need to find the highest point on the corresponding curve Y-axis. Moreover, since P0 and P2The Y-axis coordinates are the same, both are measureHeight, so the left side of the second-order curve's highest point is simplified for calculation here.

/** 
   * Get the highest point position of the Bezier curve 
   * 
   * @param y The y-coordinate of the middle control point 
   * @return 
   */ 
  private int getBsrPositionY(int y) { 
    //The starting point and endpoint are determined 
    return measureHeight + (y - measureHeight) / 2; 
  } 

Use clipPath to crop the canvas, so that the picture is displayed in an arc shape.

2. Start refreshing after releasing, flag = 3

Picture loop display, calculate the position and time interval of the picture, and switch pictures at regular intervals

mDrawableRect.set((getWidth() - drawable.getIntrinsicWidth()) / 2, 
              padding, 
              (getWidth() + drawable.getIntrinsicWidth()) / 2, 
              padding + drawable.getIntrinsicHeight()); 
          if (drawable != null) { 
            drawable.setBounds(mDrawableRect); 
            drawable.draw(canvas); 
          } 
          if (SystemClock.elapsedRealtime() - lastTime > DURATION) { 
            //Refresh animation after exceeding the interval 
            changeDrawable(); 
            lastTime = SystemClock.elapsedRealtime(); 
          } 

But if you let go here, the arc will disappear immediately, which is not very user-friendly in appearance. However, PtrFrameLayout itself has a parameter mDurationToClose, which can be understood as the time reserved for the interface to rebound to the refresh height after releasing, and some optimizations can be made within this time. Here, I have created an animation for the arc to slowly rebound based on this time value.

class MyAnimation extends Animation { 
    boolean hasStart; 
    public boolean isHasStart() { 
      return hasStart; 
    } 
    public void setHasStart(boolean hasStart) { 
      this.hasStart = hasStart; 
    } 
    @Override 
    public void initialize(int width, int height, int parentWidth, int parentHeight) { 
      super.initialize(width, height, parentWidth, parentHeight); 
      setDuration(mDurationToClose); 
      //Set the animation to retain the effect after it ends 
      setInterpolator(new AccelerateDecelerateInterpolator()); 
    } 
    @Override 
    protected void applyTransformation(float interpolatedTime, Transformation t) { 
      super.applyTransformation(interpolatedTime, t); 
      //From 0-1.gradually change (arc rebound animation), position from controlY to 0 
      flag = 3; 
      proportion = interpolatedTime; 
      invalidate(); 
    } 
  } 

 Display corresponding to onDraw

case 3: 
        //While refreshing, execute the animation of pulling up 
        if (proportion < 1.0f) { 
          mPath.reset(); 
          mPath.moveTo(0, measureHeight); 
          mPath.quadTo(getWidth(), / 2, (controlY - measureHeight) * (1 - proportion) + measureHeight, getWidth(), measureHeight); 
          mPath.lineTo(getWidth(), 0); 
          mPath.lineTo(0, 0); 
          mPath.close(); 
          canvas.drawPath(mPath, mPaint); 
          mDrawableRect.set((getWidth() - drawable.getIntrinsicWidth()) / 2, 
              (int) ((getBsrPositionY((int) controlY - drawable.getIntrinsicHeight() - padding) * (1 - proportion)) + padding, 
              (getWidth() + drawable.getIntrinsicWidth()) / 2, 
              (int) ((getBsrPositionY((int) controlY - (padding + drawable.getIntrinsicHeight())) * (1 - proportion)) + (padding + drawable.getIntrinsicHeight())); 
          if (drawable != null) { 
            drawable.setBounds(mDrawableRect); 
            drawable.draw(canvas); 
          } 
        } else {..} 

If the specific effect in the above gif is not clear, you can download the code to run it yourself. You can comment out this part and compare the two effects, and the difference is quite obvious.

3.The process of restoring after refreshing

case 4: 
        //After refreshing, the picture is changed to1,缩小了。也要保持图片的居中 
        mDrawableRect.set((getWidth() - drawable.getIntrinsicWidth()) / 2, 
            (measureHeight - drawable.getIntrinsicHeight()) / 2, 
            (getWidth() + drawable.getIntrinsicWidth()) / 2, 
            (measureHeight + drawable.getIntrinsicHeight()) / 2); 
        if (drawable != null) { 
          drawable.setBounds(mDrawableRect); 
          drawable.draw(canvas); 
        } 
        break; 

4.Initial state, not pulled down or the height of the pull-down has not reached the height of the drawing arc

case 0: 
    default: 
        //Image Position 
        mDrawableRect.set((getWidth() - drawable.getIntrinsicWidth()) / 2, 
            measureHeight - drawable.getIntrinsicHeight(), 
            (getWidth() + drawable.getIntrinsicWidth()) / 2, 
            measureHeight); 
        if (drawable != null) { 
          drawable.setBounds(mDrawableRect); 
          drawable.draw(canvas); 
        } 
        break; 

That's all for the onDraw method, and it took a lot of brain cells to calculate the drawing and display position of the image. Then add the configuration of PtrFrameLayout in the code to use it

These configuration properties can also be written in xml, and the basic customization of pull-to-refresh is completed. But don't be too happy too soon, when drawing the arc, the closed area adopts color filling, and this filling color is the paint color. This color needs to be consistent with the layout color, otherwise, try it yourself, here I did not set the background color of PtrFrameLayout, but adopted Theme, set the windowBackground color. The specific code is also included, so I won't paste it again, just in case you will have a bug if not set.

Code download address:TestUltraPullToRefresh_jb51.rar

That's all for this article. I hope it will be helpful to everyone's learning and also hope everyone will support the Yell Tutorial.

Statement: The content of this article is from the Internet, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been manually edited, and does not assume any relevant legal liability. If you find any content suspected of copyright infringement, please send an email to: notice#oldtoolbag.com (Please replace # with @ when sending an email for reporting. Provide relevant evidence, and once verified, this site will immediately delete the content suspected of infringement.)

You May Also Like