如何给SwipeRefreshLayout同时实现下拉刷新和上拉加载
来源:互联网 发布:观山4字能值多少钱知乎 编辑:程序博客网 时间:2024/06/07 02:21
尊重原创,转载请注明:http://blog.csdn.net/zj695469296/article/details/50563841
关于下拉刷新github上有很多的框架可以学习和借鉴,desmond111大神这样总结:
Repo 性能 拓展性 综合建议
PtrClassicFrameLayout
性能有缺陷;建议使用PtrFrameLayout
,性能较好。这套库自定义能力很强,建议使用。android-pulltorefresh★★实现方式上有缺陷,拓展性也很差。优点就是代码非常简单,只能作为反面例子。Phoenix★★★★★★效果非常好,性能不错,可惜比较难拓展顶部视图,为了适配布局padding造成了性能损失,有优化空间。可以作为学习与练手的对象。FlyRefresh★★★★★★效果很新颖,可惜的是顶部视图计算动效上开销太大,优化空间较少,可以作为学习与练手的对象。SwipeRefreshLayout★★★★★官方出品,更新有保障,但是如上分析,其实性能上还是有点缺陷的,拓展性比较差,不建议放入工程中使用。综合的看,现在是utltra-pull-to-refresh的天下,这套我自己也用过,十分的好用而且拓展性极高。他包含两部分:一是header,一是content,header可以自定义成任何的头部,content就是你要显示的内容了
他抽象出来了两个重要的接口:PtrHandler和PtrUIHandler,一般来说header实现PtrUIHandler接口,接口中可以为header实现在下拉开始,下拉进行中,下拉结束等状态进行相应的变化,而PtrHandler则是针对用户想要刷新数据或判断什么时候可以下拉的回调。
除此之外还有一个PtrFrameLayout这个类,他代表了一个自定义的viewgroup,有且只能有两个子view,就是header和content,跟所有的自定义控件一样会重写那几个方法,我们不需要去管他。下面贴例子:
布局文件:
<in.srain.cube.views.ptr.PtrFrameLayout android:id="@+id/rotate_header_list_view_frame" xmlns:cube_ptr="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" cube_ptr:ptr_duration_to_close="500" cube_ptr:ptr_duration_to_close_header="100" cube_ptr:ptr_keep_header_when_refresh="true" cube_ptr:ptr_pull_to_fresh="false" cube_ptr:ptr_ratio_of_header_height_to_refresh="1.2" cube_ptr:ptr_resistance="1.7"> <ListView android:id="@+id/rotate_header_list_view" android:layout_width="match_parent" android:layout_height="match_parent" android:divider="@null" android:listSelector="@android:color/transparent" android:paddingLeft="12dp" android:paddingRight="12dp" /> </in.srain.cube.views.ptr.PtrFrameLayout>代码:
final int[] i = {0}; ListView listView = (ListView) findViewById(R.id.rotate_header_list_view); final BaseAdapter baseAdapter = new BaseAdapter() { @Override public int getCount() { return 3; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { TextView textView = new TextView(MainActivity.this); textView.setText(""+ i[0]++); return textView; } }; listView.setAdapter(baseAdapter); final PtrFrameLayout mPtrFrame = (PtrFrameLayout) findViewById(R.id.rotate_header_list_view_frame); // header final MaterialHeader header = new MaterialHeader(this); int[] colors = getResources().getIntArray(R.array.google_colors); header.setColorSchemeColors(colors); //MATCH_PARENT = -1; //WRAP_CONTENT = -2; header.setLayoutParams(new PtrFrameLayout.LayoutParams(-1, -2)); LocalDisplay.init(MainActivity.this); header.setPadding(0, LocalDisplay.dp2px(15), 0, LocalDisplay.dp2px(10)); header.setPtrFrameLayout(mPtrFrame); mPtrFrame.setLoadingMinTime(2000);//设置最小的加载时间 mPtrFrame.setHeaderView(header); mPtrFrame.addPtrUIHandler(header); mPtrFrame.setPinContent(true);//不让content移动 mPtrFrame.setPtrHandler(new PtrHandler() { @Override public void onRefreshBegin(PtrFrameLayout frame) { mPtrFrame.refreshComplete(); baseAdapter.notifyDataSetChanged(); } @Override public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) { return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header); } });可以看见非常简单,utltra-pull-to-refresh的开发者liaohuqiu现在也在持续的更新,上面这里用的就是最新的material design风格的下拉刷新header,但是有个小bug,就是在header第一圈转完后会有一次明显的圆圈闪一下,然后再继续旋转,我改了两处小地方,现在能做到不闪而过,但觉得不够好,最后会有源码下载
====================================================
我这里是主推MD的下拉刷新方式的,既然上面的MD情况不够好,那么自然就找完美的方法了,还好谷歌新的v4包里退出了SwipeRefreshLayout,非常简单:
布局文件:
<android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipe_container" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/textView1" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:paddingTop="10dp" android:text="swipe_to_refresh" android:textSize="20sp" android:textStyle="bold"/> </ScrollView></android.support.v4.widget.SwipeRefreshLayout>代码:
final TextView tv = (TextView) findViewById(R.id.textView1); final SwipeRefreshLayout swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container); //设置刷新时动画的颜色,可以设置4个 swipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light, android.R.color.holo_orange_light, android.R.color.holo_green_light); swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { tv.setText("正在刷新"); // TODO Auto-generated method stub new Handler().postDelayed(new Runnable() { @Override public void run() { // TODO Auto-generated method stub tv.setText("刷新完成"); swipeRefreshLayout.setRefreshing(false); } }, 3000); } });但是注意的是在content为webview的时候,下拉会跟webview的滚动发生冲突,解决的办法也非常简单,只需要重写ontouchevent即可:
import android.content.Context;import android.support.v4.widget.SwipeRefreshLayout;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.ViewGroup;/** * 为了不让webview的滚动事件和下拉更新的事件冲突,重写onTouchEvent事件,当webview滚动到最顶端的时候才有下拉刷新 */public class ScrollSwipeRefreshLayout extends SwipeRefreshLayout { private ViewGroup viewGroup ; public ScrollSwipeRefreshLayout(Context context) { super(context); } public ScrollSwipeRefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); } public ViewGroup getViewGroup() { return viewGroup; } public void setViewGroup(ViewGroup viewGroup) { this.viewGroup = viewGroup; } @Override public boolean onTouchEvent(MotionEvent arg0) { if(null!=viewGroup){ if(viewGroup.getScrollY()> 1){ //直接截断时间传播,交给webview return false; }else{ //说明滑到了最上面,这时候就自己处理,出现下拉刷新 return super.onTouchEvent(arg0); } } return super.onTouchEvent(arg0); }}代码:
webView = (WebView) this.findViewById(R.id.webview); refreshLayout = (ScrollSwipeRefreshLayout) this.findViewById(R.id.refresh_layout); refreshLayout.setViewGroup(webView);//设置监听滚动的子view,多了这一步 refreshLayout.setOnRefreshListener(this); //设置颜色 refreshLayout.setColorScheme(R.color.green, R.color.gray, R.color.blue_50, R.color.light_white); webView.loadUrl("http://blog.csdn.net/zj695469296/article/details/50563841"); webView.setWebChromeClient(new WebChromeClient() { @Override public void onProgressChanged(WebView view, int newProgress) { super.onProgressChanged(view, newProgress); if (newProgress == 100) { //设置加载完成后结束动画 refreshLayout.setRefreshing(false); } } }); webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } });下面再多个功能,在MD风格的下拉加载完成后,再来上拉加载:
import android.content.Context;import android.support.v4.widget.SwipeRefreshLayout;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewConfiguration;import android.widget.AbsListView;import android.widget.ListView;/** * 继承自SwipeRefreshLayout,从而实现滑动到底部时上拉加载更多的功能. * 目前仅实现listview的加载更多 */public class RefreshLayout extends SwipeRefreshLayout implements AbsListView.OnScrollListener { /** * 滑动到最下面时的上拉操作 */ private int mTouchSlop; /** * listview实例 */ private ListView mListView; /** * 上拉监听器, 到了最底部的上拉加载操作 */ private OnLoadListener mOnLoadListener; /** * ListView的加载中footer */ private View mListViewFooter; /** * 按下时的y坐标 */ private int mYDown; /** * 抬起时的y坐标, 与mYDown一起用于滑动到底部时判断是上拉还是下拉 */ private int mLastY; /** * 是否在加载中 ( 上拉加载更多 ) */ private boolean isLoading = false; /** * @param context */ public RefreshLayout(Context context) { this(context, null); } public RefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); //getScaledTouchSlop表示一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。如果小于这个距离就不触发移动控件,如viewpager就是用这个距离来判断用户是否翻页 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); //拿到footer mListViewFooter = LayoutInflater.from(context).inflate(R.layout.listview_footer, null, false); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); // 初始化ListView对象 if (mListView == null) { getListView(); } } /** * 获取ListView对象 */ private void getListView() { int childs = getChildCount(); if (childs > 0) { //第一个是android.support.v4.widget.CircleImageView,SwipeRefreshLayout的下拉刷新的圆圈 //第二个才是ListView View childView = getChildAt(1); if (childView instanceof ListView) { mListView = (ListView) childView; // 设置滚动监听器给ListView, 使得滚动的情况下也可以自动加载 mListView.setOnScrollListener(this); } } } @Override public boolean dispatchTouchEvent(MotionEvent event) { final int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: // 按下 mYDown = (int) event.getRawY(); break; case MotionEvent.ACTION_MOVE: // 移动 mLastY = (int) event.getRawY(); break; case MotionEvent.ACTION_UP: // 抬起 if (canLoad()) { loadData(); } break; default: break; } return super.dispatchTouchEvent(event); } /** * 是否可以加载更多, 条件是到了最底部, listview不在加载中, 且为上拉操作. */ private boolean canLoad() { return isBottom() && !isLoading && isPullUp(); } /** * 判断是否到了最底部,这里只是判断listview的 */ private boolean isBottom() { if (mListView != null && mListView.getAdapter() != null) { return mListView.getLastVisiblePosition() == (mListView.getAdapter().getCount() - 1); } return false; } /** * 是否是上拉操作,从触摸事件中判断 */ private boolean isPullUp() { return (mYDown - mLastY) >= mTouchSlop; } /** * 如果到了最底部,而且是上拉操作.那么执行onLoad方法 */ private void loadData() { if (mOnLoadListener != null) {//只有用户设置了监听才有效果 // 设置状态为正在加载,以防重新加载 setLoading(true); mOnLoadListener.onLoad();//回调 } } /** * control footer to show or not * @param loading */ public void setLoading(boolean loading) { isLoading = loading; if (isLoading) { mListView.addFooterView(mListViewFooter); } else { mListView.removeFooterView(mListViewFooter); mYDown = 0; mLastY = 0; } } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // 滚动时到了最底部也可以加载更多 if (canLoad()) { loadData(); } } /** * 加载更多的监听器 */ public interface OnLoadListener { void onLoad(); } public void setOnLoadListener(OnLoadListener loadListener) { mOnLoadListener = loadListener; }}布局文件:
<?xml version="1.0" encoding="utf-8"?><demo.ultra_pull_to_refresh_demo.RefreshLayout android:id="@+id/swipe_layout" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView></demo.ultra_pull_to_refresh_demo.RefreshLayout>代码:
// 模拟20条数据 final List<String> datas = new ArrayList<String>(); for (int i = 0; i < 20; i++) { datas.add("item - " + i); } final BaseAdapter adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, datas); ListView listView = (ListView) findViewById(R.id.listview); listView.setAdapter(adapter); // 获取RefreshLayout实例 final RefreshLayout myRefreshListView = (RefreshLayout) findViewById(R.id.swipe_layout); // 设置下拉刷新时的颜色值,颜色值需要定义在xml中 myRefreshListView.setColorSchemeResources(R.color.color1,R.color.color2,R.color.color3,R.color.color4); // 设置下拉刷新监听器 myRefreshListView.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { Toast.makeText(MainActivity.this, "refresh", Toast.LENGTH_SHORT).show(); myRefreshListView.postDelayed(new Runnable() { @Override public void run() { // 更新数据 datas.add(new Date().toGMTString()); adapter.notifyDataSetChanged(); // 更新完后调用该方法结束刷新 myRefreshListView.setRefreshing(false); } }, 3000); } }); // 加载监听器 myRefreshListView.setOnLoadListener(new RefreshLayout.OnLoadListener() { @Override public void onLoad() { Toast.makeText(MainActivity.this, "load", Toast.LENGTH_SHORT).show(); myRefreshListView.postDelayed(new Runnable() { @Override public void run() { datas.add(new Date().toGMTString()); adapter.notifyDataSetChanged(); //让footer消失 myRefreshListView.setLoading(false); } }, 3000); } });贴图:
源码下载
0 0
- 如何给SwipeRefreshLayout同时实现下拉刷新和上拉加载
- SwipeRefreshLayout和RecyclerView实现下拉刷新和上拉加载
- SwipeRefreshLayout + RecyclerView实现上拉加载和下拉刷新
- SwipeRefreshLayout + RecyclerView 实现 上拉刷新 和 下拉加载更多
- 继承SwipeRefreshLayout实现下拉刷新和上拉加载
- SwipeRefreshLayout +RecycleView实现上拉加载更多和下拉刷新
- SwipeRefreshLayout下拉刷新和上拉加载
- Android SwipeRefreshLayout实现下拉刷新,上拉加载、滑动加载(自动加载)和点击加载
- RecyclerView和SwipeRefreshLayout下拉刷新和上拉加载
- SwipeRefreshLayout实现下拉刷新、上拉加载更多功能
- 使用SwipeRefreshLayout实现下拉刷新与上拉加载更多
- SwipeRefreshLayout+ListView实现下拉刷新自定义上拉加载
- SwipeRefreshLayout+RecyclerView实现下拉刷新上拉自动加载
- recyclerview+swiperefreshlayout实现GridView下拉刷新,上拉加载更多
- SwipeRefreshLayout+RecyclerView实现下拉刷新上拉自动加载
- android SwipeRefreshLayout 实现 下拉刷新 上拉加载
- SwipeRefreshLayout配合RecyclerView实现上拉加载更多下拉刷新
- android SwipeRefreshLayout 实现 下拉刷新 上拉加载
- UITableViewCell加载网络图片自适应cell高度初探索
- HDU3533 - Escape
- XMind和MindManager,思维导图软件学习使用心得
- Struts2学习笔记(1)之Action
- 浅谈block的基本使用和基本认知.
- 如何给SwipeRefreshLayout同时实现下拉刷新和上拉加载
- raspberry install mysql-connector-python
- 【CODEFORCES】 C. Bits
- 【慕课笔记】第七章 方法 第1节 如何定义JAVA中的方法
- UIMenuController的使用
- 寒假练习1_A
- 理论: STL(1): set
- [leetcode] 33. Search in Rotated Sorted Array
- 如果你想终结OOM崩溃,现在就安装LeakCanary!