Come play the drop-down refresh animation


Preface

You should be familiar with drop-down refresh and drop-down loading.From PulltoRefreshView in the ListView era to SwipeRefreshLayout in the RecycleView era, to encapsulated libraries on Github that accommodate a variety of Views and support both drop-down refresh and pull-up loading; you're already familiar with this.However, it is precisely because of this that the following problems are caused.

  • The effect of the implementation is single and has no characteristics of its own

This should be appreciated by those who have used the SwipeRefreshLayout provided by Google. This control works really well, it is set outside RecycleView, and the corresponding interface can easily achieve the drop-down refresh effect.However, the interaction it can achieve is very simple, even a bit boring, basically no customizable content, the most we can do is change the color of the rotated ProgressBar and its background color.

  • Integrated tripartite control, too redundant

I'm sure most people now encounter lists using RecycleView, but since SwipeRefreshLayout doesn't have the ability to pull-up loads on its own, we can only curve to save the country; either duplicate SwipeRefreshLayout itself with the ability to pull-up loads; or discard SwipeRefreshLayout and look for something else on GitHubThe latter should be the choice of many people; however, using third-party controls can also bring some additional problems, such as the weight and size of the third-party controls, the complexity of the functions, sometimes we may want to introduce some other useless code for a simple function, which is not good.

So we need a lightweight library that gives us more freedom to customize the effects of pull-down loading and pull-up refresh without overburdening us.

UltimateRefreshView

A drop-down refresh, pull-up loaded control that lets you focus on refreshing the animation effect.
Old rules, first see the effect.


Beauty Tuan Dropdown Refresh Animation

QQ drop-down animation

WebView drop-down refresh animation

There are several visually distinct animations, but one UltimateRefreshView is enough.More animation effects please Github View

function

  • Support ListView, RecycleView, ScrollView, WebView
  • A line of code specifies whether pull-up loading and drop-down refresh are supported
  • Free customization of head and tail animation during refresh

Usage

First, introduce Libraries

compile 'com.reoobter:ultrapullview:1.0.0'

Secondly, achieve their own animation effect

Here we will take the top drop-down refresh animation of Meituan APP as an example to see how to achieve the animation effect

meituan_header_refresh_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:gravity="center"
              android:background="@color/white"
              android:orientation="vertical">
    <ImageView
        android:id="@+id/loading"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_margin="10dp"
        android:scaleX="0"
        android:scaleY="0"
        android:src="@drawable/pull_image"/>
</LinearLayout>

This layout file is simple, with only one ImageView.The idea is to modify the contents of the ImageView at different nodes to present all the animation effects when the entire drop-down refresh occurs.So what are these nodes?

public class MeiTuanHeaderAdapter extends BaseHeaderAdapter {

    private ImageView loading;
    private int viewHeight;
    private float pull_distance=0;

    public MeiTuanHeaderAdapter(Context context) {
        super(context);
    }

    @Override
    public View getHeaderView() {
        View mView = mInflater.inflate(R.layout.meituan_header_refresh_layout, null, false);
        loading = (ImageView) mView.findViewById(R.id.loading);
        MeasureTools.measureView(mView);
        viewHeight = mView.getMeasuredHeight();
        return mView;
    }

    @Override
    public void pullViewToRefresh(int deltaY) {
        //This is multiplied by 0.3 because the UltimateRefreshView source has a damping factor of 0.3 for sliding, to be consistent
        pull_distance=pull_distance+deltaY*0.3f;
        float scale = pull_distance / viewHeight;
        loading.setScaleX(scale);
        loading.setScaleY(scale);

    }


    @Override
    public void releaseViewToRefresh(int deltaY) {
        loading.setImageResource(R.drawable.mei_tuan_loading_pre);
        AnimationDrawable mAnimationDrawable= (AnimationDrawable) loading.getDrawable();
        mAnimationDrawable.start();
    }

    @Override
    public void headerRefreshing() {
        loading.setImageResource(R.drawable.mei_tuan_loading);
        AnimationDrawable mAnimationDrawable= (AnimationDrawable) loading.getDrawable();
        mAnimationDrawable.start();
    }

    @Override
    public void headerRefreshComplete() {
        loading.setImageResource(R.drawable.pull_image);
        loading.setScaleX(0);
        loading.setScaleY(0);
        pull_distance=0;
    }
}

There are four important nodes that can be summarized from the code

  • As the drop-down progresses, this time as your finger slides, the entire top view gradually appears
  • The top view is completely pulled down, and by this time the top view is fully displayed, and the finger is released (lifted) before it enters the next node.
  • When refresh is in progress, when refresh is in progress, this node is when the refresh animation is executed.
  • Refresh complete, at which point the action of refresh complete is triggered

In order to achieve the effect of refreshing the animation on the top of Meituan, we start the animation at the first node and use the scale animation to gradually enlarge the initial picture (green ellipse) according to the refreshing displacement ratio. In the second node, this node is usually very short, at this time the top is fully displayed and the little flip is performed.The resulting animation; in the third node, this node is generally time-consuming, where a little doll swings from side to side with a frame animation; and finally, in the fourth node, all content is initialized to the state before the drop-down to facilitate the next drop-down star animation.This completes a drop-down refresh animation.

Now you can easily apply this animation effect to View.

Finally, the animation effect is adapted to the UltimateRefreshView

Here's a ListView example.

First is the layout implementation:

<FrameLayout 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"
             android:background="@color/white"
             tools:context=".subfragment.ListViewFragment"
    >

    <com.sak.ultilviewlib.UltimateRefreshView
        android:id="@+id/refreshView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:orientation="vertical">

        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="none"/>

    </com.sak.ultilviewlib.UltimateRefreshView>

</FrameLayout>

Layout files are simple, just place the controls you want to implement in the UltimateRefreshView control.

public class ListViewFragment extends Fragment {
    private UltimateRefreshView mUltimateRefreshView;

    private int page = 0;
    private int PER_PAGE_NUM = 15;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_list_view, container, false);
        initView(view);
        return view;
    }

    private void initView(View view) {
        View headview = LayoutInflater.from(getContext()).inflate(R.layout.list_headview_layout,
                null, false);
        ListView listView = (ListView) view.findViewById(R.id.listView);
        final List<String> datas = new ArrayList<>();
        for (int i = 0; i < PER_PAGE_NUM; i++) {
            datas.add("this is item " + i);
        }
        final ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, datas);
        listView.setAdapter(adapter);
        listView.addHeaderView(headview);
        mUltimateRefreshView = (UltimateRefreshView) view.findViewById(R.id.refreshView);
        mUltimateRefreshView.setBaseHeaderAdapter(new MeiTuanHeaderAdapter(getContext()));
        mUltimateRefreshView.setBaseFooterAdapter();
        mUltimateRefreshView.setOnHeaderRefreshListener(new OnHeaderRefreshListener() {
            @Override
            public void onHeaderRefresh(UltimateRefreshView view) {
                page = 0;
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        datas.clear();
                        for (int i = page * PER_PAGE_NUM; i < PER_PAGE_NUM; i++) {
                            datas.add("this is item " + i);
                        }
                        adapter.notifyDataSetChanged();
                        mUltimateRefreshView.onHeaderRefreshComplete();
                    }
                }, 2000);
            }
        });

        mUltimateRefreshView.setOnFooterRefreshListener(new OnFooterRefreshListener() {
            @Override
            public void onFooterRefresh(UltimateRefreshView view) {
                page++;
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        for (int i = page * PER_PAGE_NUM; i < (page + 1) * PER_PAGE_NUM; i++) {
                            datas.add("this is item " + i);
                        }
                        adapter.notifyDataSetChanged();
                        mUltimateRefreshView.onFooterRefreshComplete();
                    }
                }, 200);
            }
        });
    }

}

The key code here is:

        mUltimateRefreshView.setBaseHeaderAdapter(new MeiTuanHeaderAdapter(getContext()));
        mUltimateRefreshView.setBaseFooterAdapter();

In this way, the ListView is animated with drop-down refresh and drop-down load.

For ease of use, a nonreferential setAdapter method is provided that uses the default animation effect when no parameters are provided.

Here, the drop-down refresh uses the MeiTuanHeaderAdapter effect we just defined, while the pull-up effect uses the default effect; of course, if you don't need the pull-up or pull-down refresh effect, you can just leave the corresponding Adapter untouched.That is, no execution (setBaseFooterAdapter and setBaseHeaderAdapter methods)

Finally, set the listener for the execution of the property animation for the mUltimateRefreshView. This callback method is called when the animation is refreshed (that is, when the execution starts at the third node mentioned above). In this method we usually make network requests or some time-consuming operations. Here we use Handler simulationA simple time-consuming task that calls the corresponding refresh completion method when the time-consuming operation is complete so that either a drop-down refresh or a pull-up load is completed (that is, the fourth node mentioned above).

This article focuses on the implementation of animation effect during the whole refresh process, and does not focus on how to refresh data when dropping down or pulling up.

When we need a drop-down refresh animation, we can inherit the BaseHeaderAdapter class and make different implementations in each method (that is, each node of a drop-down event) according to the effect the animation needs.

Similarly, inherit the BaseFooterAdapter when a pull-up loading animation is required.The definition of nodes in the BaseFooterAdapter class is exactly the same as in the BaseHeaderAdapter class, except that the sliding direction changes from drop-down to pull-up.Here is a simple simulation of the animation effect when Jingdong pulls up to load.

package com.sak.app.adapter;

import android.content.Context;
import android.view.View;
import android.widget.ImageView;

import com.bumptech.glide.Glide;
import com.sak.app.R;
import com.sak.ultilviewlib.adapter.BaseFooterAdapter;

/**
 * Created by engineer on 2017/4/30.
 */

public class JDAppFooterAdapter extends BaseFooterAdapter {
    private ImageView loading;
    private Context mContext;

    public JDAppFooterAdapter(Context context) {
        super(context);
        mContext=context;
    }

    @Override
    public View getFooterView() {
        View footerView = mInflater.inflate(R.layout.jd_footer_refresh_layout, null, false);
        loading = (ImageView) footerView.findViewById(R.id.loading);
        return footerView;
    }

    @Override
    public void pullViewToRefresh(int deltaY) {
        Glide.with(mContext).load(R.drawable.jd_loading_logo).into(loading);
    }

    @Override
    public void releaseViewToRefresh(int deltaY) {

    }

    @Override
    public void footerRefreshing() {

    }

    @Override
    public void footerRefreshComplete() {
        loading.setImageDrawable(null);
    }
}

Here we inherit the BaseFooterAdapter and see that it is very similar to the BaseHeaderAdapter.For convenience, there is no very complex implementation. At the beginning of the pull-up execution, a gif animation was loaded with Glide by accident, so that a simple animation would appear when the pull-up was executed.Now users usually finish loading paging data very quickly when they pull up, but the implementation of pull-up animation is not too complicated.

More can be referred to Source code Implementation of demo in.

summary

As you can see, the way we set the animation refresh is on the mUltimateRefreshView, that is, whether it's a ListView nested inside the mUltimateRefreshView, or a RecycleView or a ScrollView.Animation effects on the head and tail are completely unaffected by nested subviews.Therefore, we can focus more on the brilliant animation of the head and tail refresh than on the handling of various sliding events.

The implementation of head and tail animations is completely separate from the mUltimateRefreshView itself, greatly reducing coupling.What kind of animation you need can be set by setBaseFooterAdapter and setBaseHeaderAdapter methods, which are very flexible and allow you to mix different head and tail animations freely.

So, come and play!

Finally, give it again Github Source .Welcome interested students, Star & fork.

Keywords: Android github xml Fragment

Added by Chris16962 on Wed, 03 Jul 2019 19:32:01 +0300