This is the second in a series of articles. Project address: github.com/cachecats/L…

Android extracts Gradle dependencies from zero to a single file

Android from zero meituantuan (3) – Android multi-tab TAB slide toggle – custom View quickly achieve a highly customized package

Banner+ custom View+SmartRefreshLayout pull down refresh up load more


Today I wrote a drop-down refresh, and the framework uses SmartRefreshLayout. I don’t know why, because it has 9.5K stars on Github and supports Chinese to save time.

First above:

A, analysis,

Meituan’s pull-down loading animation looks very simple at first glance, just a cute little man. If you look at it a little bit more complicated, there are three states.

  1. At the beginning of the pull-down, the process by which the small brain grows from small to large.
  2. After pulling down enough but not letting go, the little man did a somersault until he was fully visible. Scroll down again to keep the last full appearance.
  3. After loosening, shake your head from side to side until the end of loading and bouncing back.

That’s three animations! Really admire these big factories, simple loading animation are so complicated.

After analyzing the process, it’s time to think about how to implement it.

Second, decompile APP to see the implementation principle

The simplest and most straightforward way is to decompile the Meituan app. Although you can’t see the code, the resource files can be restored. Images and XML files can be restored perfectly.

Decompiler tool is apktool, the use of methods are available on the official website is not wordy.

Most of the pictures are stored in res/drawable- xhdpi-V4 and RES /drawable- xxhdpi-V4 folders. If you look carefully, you can see many consecutive loading pictures. Here to meituan program ape point of praise, the file name is very standard, very easy to find ~

When I saw the picture, I realized that it used the most ordinary frame animation, which is not too complicated. Get the resource picture, know the implementation principle, and start working!

Three, to achieve the animation effect

First customize the View CustomRefreshHeader from the LinearLayout and implement the RefreshHeader interface of SmartRefreshLayout. The main thing to do then is to rewrite the methods in the RefreshHeader interface, which provides callbacks for different stages of the drop-down refresh, just find the corresponding method code.

public class CustomRefreshHeader extends LinearLayout implements RefreshHeader {

    private ImageView mImage;
    private AnimationDrawable pullDownAnim;
    private AnimationDrawable refreshingAnim;

    private boolean hasSetPullDownAnim = false;

    public CustomRefreshHeader(Context context) {
        this(context, null, 0);
    }

    public CustomRefreshHeader(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomRefreshHeader(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        View view = View.inflate(context, R.layout.widget_custom_refresh_header, this);
        mImage = (ImageView) view.findViewById(R.id.iv_refresh_header);
    }

    @NonNull
    @Override
    public View getView() {
        return this;
    }

    @Override
    public SpinnerStyle getSpinnerStyle() {
        returnSpinnerStyle.Translate; } @override public void onStartAnimator(RefreshLayout Layout, int height, int extendHeight) {} RefreshLayout @param oldState @param newState @override public void onStateChanged(RefreshLayout refreshLayout, RefreshState oldState, RefreshState newState) { switch (newState) {casePullDownToRefresh: // The pulldown refresh starts. SetImageResource (R.drawable.commonui_pull_image); // Set the image resource to mimage.setimageresource (R.drawable.commonui_pull_image);break;
            caseRefreshing: // Refreshing. Call // once and set the resource to mimage.setimageresource (r.dvable. Anim_pull_refreshing) when the state is being refreshed. refreshingAnim = (AnimationDrawable) mImage.getDrawable(); refreshingAnim.start();break;
            case ReleaseToRefresh:

                break; }} /** * this method is called repeatedly during the dropdown. */ @override public void onPullingDown()float percent, int offset, int headerHeight, int extendHeight) {
        Logger.d("percent: "+ percent); // Keep calling when the percentage of pull-down is less than 100%setThe Scale method changes the size of the imageif(percent < 1) { mImage.setScaleX(percent); mImage.setScaleY(percent); // Whether the somersault animation was executedif (hasSetPullDownAnim) {
                hasSetPullDownAnim = false; }} // When the pull-down height reaches 100% of the Header height, the initial animation that is being pulled down, i.e. the somersault, begins to loadif(percent >= 1.0) {// Since this method is called continuously, it prevents repetitionif(! hasSetPullDownAnim) { mImage.setImageResource(R.drawable.anim_pull_end); pullDownAnim = (AnimationDrawable) mImage.getDrawable(); pullDownAnim.start(); hasSetPullDownAnim =true; }} /* Override public int onFinish(RefreshLayout Layout, Boolean success) {// Finish the animationif(pullDownAnim ! = null && pullDownAnim.isRunning()) { pullDownAnim.stop(); }if(refreshingAnim ! = null && refreshingAnim.isRunning()) { refreshingAnim.stop(); } // Reset the state hasSetPullDownAnim =false;
        return 0;
    }

    @Override
    public void onReleasing(float percent, int offset, int headerHeight, int extendHeight) {

    }

    @Override
    public void onRefreshReleased(RefreshLayout layout, int headerHeight, int extendHeight) {

    }

    @Override
    public void setPrimaryColors(int... colors) {

    }

    @Override
    public void onInitialized(RefreshKernel kernel, int height, int extendHeight) {

    }

    @Override
    public void onHorizontalDrag(float percentX, int offsetX, int offsetMax) {

    }

    @Override
    public boolean isSupportHorizontalDrag() {
        return false; }}Copy the code

The logic is in onStateChanged() and onPullingDown(), and the comments are detailed in the code. AnimationDrawable: AnimationDrawable: AnimationDrawable: AnimationDrawable: AnimationDrawable: AnimationDrawable: AnimationDrawable: AnimationDrawable: AnimationDrawable: AnimationDrawable

mImage.setImageResource(R.drawable.anim_pull_end);
pullDownAnim = (AnimationDrawable) mImage.getDrawable();
pullDownAnim.start();
Copy the code

Call from code:

smartRefreshLayout.setRefreshHeader(new CustomRefreshHeader(getActivity()));
        smartRefreshLayout.setOnRefreshLoadmoreListener(new OnRefreshLoadmoreListener() {
            @Override
            public void onLoadmore(RefreshLayout refreshlayout) {
                Logger.d("onLoadmore");
                smartRefreshLayout.finishLoadmore(2000, true);
            }

            @Override
            public void onRefresh(RefreshLayout refreshlayout) {
                Logger.d("onRefresh");
                smartRefreshLayout.finishRefresh(2000, true); }});Copy the code

Paste the resource layout file: widget_custom_refresh_header.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:background="@color/white"
    android:gravity="center"
    android:padding="5dp">

    <ImageView
        android:id="@+id/iv_refresh_header"
        android:layout_width="41dp"
        android:layout_height="54dp"
        android:scaleX="0"
        android:scaleY="0"
        android:translationY="0dp" />

</LinearLayout>
Copy the code

anim_pull_end.xml

<? xml version="1.0" encoding="utf-8"? > <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">

    <item
        android:drawable="@drawable/commonui_pull_end_image_frame_01"
        android:duration="100" />

    <item
        android:drawable="@drawable/commonui_pull_end_image_frame_02"
        android:duration="100" />

    <item
        android:drawable="@drawable/commonui_pull_end_image_frame_03"
        android:duration="100" />

    <item
        android:drawable="@drawable/commonui_pull_end_image_frame_04"
        android:duration="100" />

    <item
        android:drawable="@drawable/commonui_pull_end_image_frame_05"
        android:duration="100" />

</animation-list>
Copy the code

anim_pull_refreshing.xml

<? xml version="1.0" encoding="utf-8"? > <animation-list android:oneshot="false"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:duration="50" android:drawable="@drawable/commonui_refreshing_image_frame_01" />
    <item android:duration="50" android:drawable="@drawable/commonui_refreshing_image_frame_02" />
    <item android:duration="50" android:drawable="@drawable/commonui_refreshing_image_frame_03" />
    <item android:duration="50" android:drawable="@drawable/commonui_refreshing_image_frame_02" />
    <item android:duration="50" android:drawable="@drawable/commonui_refreshing_image_frame_05" />
    <item android:duration="50" android:drawable="@drawable/commonui_refreshing_image_frame_06" />
    <item android:duration="50" android:drawable="@drawable/commonui_refreshing_image_frame_07" />
    <item android:duration="50" android:drawable="@drawable/commonui_refreshing_image_frame_06" />
</animation-list>
Copy the code

Well, the above is the implementation process of the meituan drop-down refresh custom animation. Source code address: github.com/cachecats/L…