1. 程式人生 > >自定義動畫下拉重新整理,可仿美團、京東

自定義動畫下拉重新整理,可仿美團、京東

效果
這裡寫圖片描述
功能

支援ListView,RecycleView,ScrollView,WebView
一行程式碼指定是否支援上拉載入,下拉重新整理
自由定製重新整理時頭部和尾部的動畫效果

使用方式

首先,是引入庫

compile 'com.reoobter:ultrapullview:1.0.0'

其次,實現各自的動畫效果

這裡我們就以美團APP頂部下拉重新整理的動畫為例來看看如何實現動畫效果

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>

這個佈局檔案很簡單,整個只有一個ImageView。我們的實現思路,就是在不同的結點修改ImageView的內容,從而呈現出整個下拉重新整理時所有的動畫效果。那麼這些結點是哪些呢?

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) {
        //這裡乘以0.3 是因為UltimateRefreshView 原始碼中對於滑動有0.3的阻尼係數,為了保持一致
        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;
    }
}

通過程式碼我們可以總結出有4個重要的結點

下拉進行時,這個時候隨著手指滑動,整個頂部的view逐漸顯示出來
頂部view完全被下拉出來,這個時候頂部view已經完全顯示出來了,手指釋放(擡起)後將進入下一個結點。
正在重新整理進行時,重新整理進行時,這個結點就是重新整理動畫執行的時候。
重新整理完成,在這個結點觸發了重新整理完成的動作

為了實現美團頂部重新整理動畫的效果,在第一個結點我們便開始執行動畫,根據重新整理的位移比,使用scale動畫逐漸放大初始圖片(綠色橢圓);在第二個結點,這個結點一般都很短暫,這個時候頂部已經完全展示,執行了小人偶翻轉出現的動畫;在第三個結點,這個結點一般是比較耗時的,在這裡用幀動畫播放了一個小人偶左右搖擺的動畫;最後,在第四個結點,將所有內容初始化到下拉之前的狀態,方便下次下拉刷星動畫的執行。這樣就完成了一次下拉重新整理的動畫效果。

最後,將動畫效果適配到UltimateRefreshView之上

這裡就以ListView為例。

首先是佈局實現:

<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>

佈局檔案很簡單,將所要實現的下拉重新整理的控制元件放在UltimateRefreshView控制元件內即可。

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);
            }
        });
    }

}