{"id":13641551,"url":"https://github.com/REBOOTERS/UltimateRefreshView","last_synced_at":"2025-04-20T11:31:13.783Z","repository":{"id":97476110,"uuid":"89663837","full_name":"REBOOTERS/UltimateRefreshView","owner":"REBOOTERS","description":"UltimateRefreshView 实现下拉刷新，上拉加载更多的轻量级库；支持RecyclerView ,ListView ,ScrollView \u0026 WebView ","archived":false,"fork":false,"pushed_at":"2017-08-04T09:09:43.000Z","size":6644,"stargazers_count":68,"open_issues_count":3,"forks_count":18,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-28T10:49:49.729Z","etag":null,"topics":["listview","pull-to-refresh","recyclerview","scrollview","webview"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/REBOOTERS.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-04-28T03:28:15.000Z","updated_at":"2023-09-24T03:27:09.000Z","dependencies_parsed_at":"2024-01-14T11:07:22.409Z","dependency_job_id":"551574b9-9ffe-4f3e-bebc-62d02e1f3661","html_url":"https://github.com/REBOOTERS/UltimateRefreshView","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/REBOOTERS%2FUltimateRefreshView","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/REBOOTERS%2FUltimateRefreshView/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/REBOOTERS%2FUltimateRefreshView/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/REBOOTERS%2FUltimateRefreshView/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/REBOOTERS","download_url":"https://codeload.github.com/REBOOTERS/UltimateRefreshView/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223827397,"owners_count":17209787,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["listview","pull-to-refresh","recyclerview","scrollview","webview"],"created_at":"2024-08-02T01:01:21.707Z","updated_at":"2024-11-09T12:30:26.030Z","avatar_url":"https://github.com/REBOOTERS.png","language":"Java","readme":"\n[ ![Download](https://api.bintray.com/packages/rookieboy/maven/ultrapullview/images/download.svg?version=1.0.1) ](https://bintray.com/rookieboy/maven/ultrapullview/1.0.1/link)\n\n\n\n# UltimateRefreshView\n\n### 预览\n\n\u003cimg src=\"https://raw.githubusercontent.com/REBOOTERS/UltimateRefreshView/master/captures/listview_pull_down.gif\"/\u003e\n\n### 功能\n\n- 支持ListView，RecycleView，ScrollView，WebView \n- 一行代码指定是否支持上拉加载，下拉刷新\n- 自由定制刷新时头部和尾部的动画效果\n\n### 使用方式\n\n**首先，是引入库**\n\n```\ncompile 'com.reoobter:ultrapullview:1.0.0'\n```\n\n**其次，实现各自的动画效果**\n\n这里我们就以美团APP顶部下拉刷新的动画为例来看看如何实现动画效果\n\n\n*meituan_header_refresh_layout.xml*\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003cLinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"wrap_content\"\n              android:gravity=\"center\"\n              android:background=\"@color/white\"\n              android:orientation=\"vertical\"\u003e\n    \u003cImageView\n        android:id=\"@+id/loading\"\n        android:layout_width=\"50dp\"\n        android:layout_height=\"50dp\"\n        android:layout_margin=\"10dp\"\n        android:scaleX=\"0\"\n        android:scaleY=\"0\"\n        android:src=\"@drawable/pull_image\"/\u003e\n\u003c/LinearLayout\u003e\n```\n\n这个布局文件很简单，整个只有一个ImageView。我们的实现思路，就是在不同的结点修改ImageView的内容，从而呈现出整个下拉刷新时所有的动画效果。那么这些**结点**是哪些呢？\n\n```java\npublic class MeiTuanHeaderAdapter extends BaseHeaderAdapter {\n\n    private ImageView loading;\n    private int viewHeight;\n    private float pull_distance=0;\n\n    public MeiTuanHeaderAdapter(Context context) {\n        super(context);\n    }\n\n    @Override\n    public View getHeaderView() {\n        View mView = mInflater.inflate(R.layout.meituan_header_refresh_layout, null, false);\n        loading = (ImageView) mView.findViewById(R.id.loading);\n        MeasureTools.measureView(mView);\n        viewHeight = mView.getMeasuredHeight();\n        return mView;\n    }\n\n    @Override\n    public void pullViewToRefresh(int deltaY) {\n        //这里乘以0.3 是因为UltimateRefreshView 源码中对于滑动有0.3的阻尼系数，为了保持一致\n        pull_distance=pull_distance+deltaY*0.3f;\n        float scale = pull_distance / viewHeight;\n        loading.setScaleX(scale);\n        loading.setScaleY(scale);\n\n    }\n\n\n    @Override\n    public void releaseViewToRefresh(int deltaY) {\n        loading.setImageResource(R.drawable.mei_tuan_loading_pre);\n        AnimationDrawable mAnimationDrawable= (AnimationDrawable) loading.getDrawable();\n        mAnimationDrawable.start();\n    }\n\n    @Override\n    public void headerRefreshing() {\n        loading.setImageResource(R.drawable.mei_tuan_loading);\n        AnimationDrawable mAnimationDrawable= (AnimationDrawable) loading.getDrawable();\n        mAnimationDrawable.start();\n    }\n\n    @Override\n    public void headerRefreshComplete() {\n        loading.setImageResource(R.drawable.pull_image);\n        loading.setScaleX(0);\n        loading.setScaleY(0);\n        pull_distance=0;\n    }\n}\n```\n\n通过代码我们可以总结出有**4个**重要的结点\n\n- **下拉进行时**，这个时候随着手指滑动，整个顶部的view逐渐显示出来\n- **顶部view完全被下拉出来**，这个时候顶部view已经完全显示出来了，手指释放（抬起）后将进入下一个结点。\n- **正在刷新进行时**，刷新进行时，这个结点就是刷新动画执行的时候。\n- **刷新完成**，在这个结点触发了刷新完成的动作\n\n\n为了实现美团顶部刷新动画的效果，在**第一个结点**我们便开始执行动画，根据刷新的位移比，使用scale动画逐渐放大初始图片（绿色椭圆）；在**第二个结点**，这个结点一般都很短暂，这个时候顶部已经完全展示，执行了小人偶翻转出现的动画；在**第三个结点**，这个结点一般是比较耗时的，在这里用帧动画播放了一个小人偶左右摇摆的动画；最后，在**第四个结点**，将所有内容初始化到下拉之前的状态，方便下次下拉刷星动画的执行。这样就完成了一次下拉刷新的动画效果。\n\n\n**最后，将动画效果适配到UltimateRefreshView之上**\n\n这里就以ListView为例。\n\n首先是布局实现：\n\n```xml\n\u003cFrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n             xmlns:tools=\"http://schemas.android.com/tools\"\n             android:layout_width=\"match_parent\"\n             android:layout_height=\"match_parent\"\n             android:background=\"@color/white\"\n             tools:context=\".subfragment.ListViewFragment\"\n    \u003e\n\n    \u003ccom.sak.ultilviewlib.UltimateRefreshView\n        android:id=\"@+id/refreshView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@color/white\"\n        android:orientation=\"vertical\"\u003e\n\n        \u003cListView\n            android:id=\"@+id/listView\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:scrollbars=\"none\"/\u003e\n\n    \u003c/com.sak.ultilviewlib.UltimateRefreshView\u003e\n\n\u003c/FrameLayout\u003e\n```\n\n布局文件很简单，将所要实现的下拉刷新的控件放在UltimateRefreshView控件内即可。\n\n```java\npublic class ListViewFragment extends Fragment {\n    private UltimateRefreshView mUltimateRefreshView;\n\n    private int page = 0;\n    private int PER_PAGE_NUM = 15;\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        View view = inflater.inflate(R.layout.fragment_list_view, container, false);\n        initView(view);\n        return view;\n    }\n\n    private void initView(View view) {\n        View headview = LayoutInflater.from(getContext()).inflate(R.layout.list_headview_layout,\n                null, false);\n        ListView listView = (ListView) view.findViewById(R.id.listView);\n        final List\u003cString\u003e datas = new ArrayList\u003c\u003e();\n        for (int i = 0; i \u003c PER_PAGE_NUM; i++) {\n            datas.add(\"this is item \" + i);\n        }\n        final ArrayAdapter\u003cString\u003e adapter = new ArrayAdapter\u003cString\u003e(getContext(), android.R.layout.simple_list_item_1, datas);\n        listView.setAdapter(adapter);\n        listView.addHeaderView(headview);\n        mUltimateRefreshView = (UltimateRefreshView) view.findViewById(R.id.refreshView);\n        mUltimateRefreshView.setBaseHeaderAdapter(new MeiTuanHeaderAdapter(getContext()));\n        mUltimateRefreshView.setBaseFooterAdapter();\n        mUltimateRefreshView.setOnHeaderRefreshListener(new OnHeaderRefreshListener() {\n            @Override\n            public void onHeaderRefresh(UltimateRefreshView view) {\n                page = 0;\n                new Handler().postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        datas.clear();\n                        for (int i = page * PER_PAGE_NUM; i \u003c PER_PAGE_NUM; i++) {\n                            datas.add(\"this is item \" + i);\n                        }\n                        adapter.notifyDataSetChanged();\n                        mUltimateRefreshView.onHeaderRefreshComplete();\n                    }\n                }, 2000);\n            }\n        });\n\n        mUltimateRefreshView.setOnFooterRefreshListener(new OnFooterRefreshListener() {\n            @Override\n            public void onFooterRefresh(UltimateRefreshView view) {\n                page++;\n                new Handler().postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        for (int i = page * PER_PAGE_NUM; i \u003c (page + 1) * PER_PAGE_NUM; i++) {\n                            datas.add(\"this is item \" + i);\n                        }\n                        adapter.notifyDataSetChanged();\n                        mUltimateRefreshView.onFooterRefreshComplete();\n                    }\n                }, 200);\n            }\n        });\n    }\n\n}\n```\n\n## 效果图\n\n\n\n\u003cimg src=\"https://raw.githubusercontent.com/REBOOTERS/UltimateRefreshView/master/captures/GIF.gif\"/\u003e\n\n\u003cimg src=\"https://raw.githubusercontent.com/REBOOTERS/UltimateRefreshView/master/captures/webview_pull_downgif.gif\"/\u003e\n\n\u003cimg src=\"https://raw.githubusercontent.com/REBOOTERS/UltimateRefreshView/master/captures/ddmsrec_clip.gif\"/\u003e\n\n\u003cimg src=\"https://raw.githubusercontent.com/REBOOTERS/UltimateRefreshView/master/captures/normal.gif\"/\u003e\n\n\u003cimg src=\"https://raw.githubusercontent.com/REBOOTERS/UltimateRefreshView/master/captures/pull_up.gif\"/\u003e\n\n\n[更多详细说明](http://www.jianshu.com/p/4343492c01f7)\n","funding_links":[],"categories":["下拉刷新"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FREBOOTERS%2FUltimateRefreshView","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FREBOOTERS%2FUltimateRefreshView","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FREBOOTERS%2FUltimateRefreshView/lists"}