Android 5.0 之SwipeRefreshLayout

金田

下拉刷新是一种比较常用的效果,Android 5.0之前官方并未提供类似的控件,App中主要是用的第三方库,例如PullToRefresh,ActionBar-PullToRefresh等。刚好现在项目中需要处理 Android 5.0 材质设计部分的东西,就顺带学习下这部分。

大体介绍一下;

  1. SwipeRefreshLayout是Google在support v4 19.1版本的library更新的一个下拉刷新控件 (android-support-v4.jar)
  2. 目前只支持下拉刷新,不支持上拉加载更多的操作(需要自行进行扩展)
  3. 作为官方自带的控件,相对能能够保证比较好的通用性及风格(这里不包括各种自家定制的系统 L)
  4. SwipeRefreshLayout继承于ViewGroup,ViewGroup中可以包含其他不同控件,so UI定制起来也相对比较容易
  5. 使用起来比较方便,可以很容易的实现Google Now的刷新效果

        SwipeRefreshLayout布局中目前只能包含一个子布局,使用侦听机制来通知刷新事件。例如当用户使用下拉手势时,SwipeRefreshLayout会触发OnRefreshListener,然后刷新事件会在onRefresh()方法中进行处理。当需要结束刷新的时候,可以调用setRefreshing(false)。如果要禁用手势和进度动画,调用setEnabled(false)即可。

 

接下来介绍一下其大体使用方法:

1.布局文件(示例代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version= "1.0" encoding= "utf-8" ?>
<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.support.v4.widget.SwipeRefreshLayout
         android:id= "@+id/id_explore_swipe_ly"
         android:layout_width= "wrap_content"
         android:layout_height= "wrap_content"
         android:background= "#ffffff" >
 
         <ListView
             android:id= "@+id/id_listview"
             android:layout_width= "match_parent"
             android:layout_height= "match_parent" >
         </ListView>
     </android.support.v4.widget.SwipeRefreshLayout>
 
</FrameLayout>

2.java逻辑代码:

首先需要实现 SwipeRefreshLayout.OnRefreshListener  接口,然后重写方法 onRefresh():

1
2
3
4
5
6
7
8
9
10
11
@Override
public void onRefresh() {
     new Handler().postDelayed( new Runnable() {
 
         @Override
         public void run() {
             // 设置SwipeRefreshLayout当前是否处于刷新状态,一般是在请求数据的时候设置为true,在数据被加载到View中后,设置为false。
             mSwipeRefreshLayout.setRefreshing( false );
         }
     }, 3000 );
}

 

现在我们初始化该控件:

1
2
3
4
5
6
7
8
9
10
public void initSwipeRefreshParameters() {
     // 设置进度条的颜色变化,最多可以设置4种颜色
  mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_green_dark, android.R.color.holo_green_light,
             android.R.color.holo_orange_light, android.R.color.holo_red_light);
     // 设置下拉监听,当用户下拉的时候会去执行回调
     mSwipeRefreshLayout.setOnRefreshListener( this );
     // 调整进度条距离屏幕顶部的距离
     mSwipeRefreshLayout.setProgressViewOffset( false , 0 ,
             ( int ) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24 , getResources().getDisplayMetrics()));
}

 

以上是基本用法,现在来大体介绍一下定制支持上拉加载的部分,演示图示:

图1 上拉加载效果示意图

 

首先实现SwipeRefreshLayout的重写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
public class mySwipeRefreshLayout extends SwipeRefreshLayout implements OnScrollListener {
 
     private int mTouchSlop;
     private ListView mListView;
     private OnLoadListener mOnLoadListener;
     private View mListViewFooter;
     private int mYDown;
     private int mLastY;
     private boolean isLoading = false ;
 
     public mySwipeRefreshLayout(Context context) {
         this (context, null );
     }
 
     public mySwipeRefreshLayout(Context context, AttributeSet attrs) {
         super (context, attrs);
 
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
 
         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();
         }
     }
 
     private void getListView() {
         int childs = getChildCount();
         if (childs > 0 ) {
             View childView = getChildAt( 0 );
             if (childView instanceof ListView) {
                 mListView = (ListView) childView;
                 // 设置滚动监听器给ListView, 使得滚动的情况下也可以自动加载
                 mListView.setOnScrollListener( this );
             }
         }
     }
 
     public void setListView(ListView list) {
         this .mListView = list;
         setLoading( true );
         this .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();
     }
 
     /**
      * @方法说明:判断是否到了最底部
      */
     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 ) {
             mOnLoadListener.onLoad();
         }
         // 设置状态
         setLoading( true );
     }
 
     /**
      * @方法说明:设置刷新
      */
     public void setLoading( boolean loading) {
         isLoading = loading;
         if (mListView != null && mListView.getFooterViewsCount() > 0 )
             mListView.removeFooterView(mListViewFooter);
         if (isLoading) {
             if (mListView != null && mListView.getFooterViewsCount() <= 0 )
                 mListView.addFooterView(mListViewFooter);
         } else {
             mYDown = 0 ;
             mLastY = 0 ;
         }
     }
 
     public void setOnLoadListener(OnLoadListener loadListener) {
         mOnLoadListener = loadListener;
     }
 
     @Override
     public void onScrollStateChanged(AbsListView view, int scrollState) {
     }
 
     @Override
     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
         if (isFastDoubleClick( 100 ))
             return ;
 
         // 滚动时到了最底部也可以加载更多
         isLoading = false ;
         if (canLoad()) {
             loadData();
         }
     }
 
     public View getmListViewFooter() {
         return mListViewFooter;
     }
 
     /**
      * @类描述:加载更多的监听器
      */
     public static interface OnLoadListener {
         public void onLoad();
     }
 
     private static long lastClickTime;
 
     public static boolean isFastDoubleClick( long times) {
         long time = System.currentTimeMillis();
         long timeD = time - lastClickTime;
         if ( 0 < timeD && timeD < times) {
             return true ;
         }
         lastClickTime = time;
         return false ;
     }
}

 

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
public class MainActivity extends Activity {
     private mydapter adapter;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
 
         setContentView(R.layout.main);
         adapter = new mydapter();
 
         // 获取RefreshLayout实例
         final mySwipeRefreshLayout myRefreshListView = (mySwipeRefreshLayout) findViewById(R.id.swipe_layout);
 
         // 获取listview实例
         ListView listView = (ListView) findViewById(R.id.listview);
         myRefreshListView.setListView(listView);
         listView.setAdapter(adapter);
 
         // 设置进度条的颜色变化,最多可以设置4种颜色
    myRefreshListView.setColorSchemeResources(android.R.color.holo_green_dark, android.R.color.holo_green_light,
                 android.R.color.holo_orange_light, android.R.color.holo_red_light);
         // 设置下拉刷新监听器
         myRefreshListView.setOnRefreshListener( new OnRefreshListener() {
 
             @Override
             public void onRefresh() {
                 Toast.makeText(MainActivity. this , "refresh" , Toast.LENGTH_SHORT).show();
                 myRefreshListView.postDelayed( new Runnable() {
 
                     @Override
                     public void run() {
                         // 更新完后调用该方法结束刷新
                         myRefreshListView.setRefreshing( false );
 
                         adapter.getData().clear();
                         // 模拟一些数据
                         for ( int i = 0 ; i < 20 ; i++) {
                             adapter.addData( "liu hhh " + i);
                         }
                     }
                 }, 1000 );
             }
         });
 
         // 加载监听器
         myRefreshListView.setOnLoadListener( new OnLoadListener() {
 
             @Override
             public void onLoad() {
                 myRefreshListView.postDelayed( new Runnable() {
                     @Override
                     public void run() {
                         // 加载完后调用该方法
                         adapter.addData( new Date().toGMTString());
                         adapter.notifyDataSetChanged();
                         myRefreshListView.setLoading( false );
                     }
                 }, 1500 );
             }
         });
     }
 
     class mydapter extends BaseAdapter {
         List<String> datas = new ArrayList<String>();
 
         public mydapter() {
             // 模拟一些数据
             for ( int i = 0 ; i < 20 ; i++) {
                 datas.add( "item - " + i);
             }
         }
 
         public void setData(List<String> data) {
             this .datas = data;
             notifyDataSetChanged();
         }
 
         public void addData(String str) {
             this .datas.add(str);
             notifyDataSetChanged();
         }
 
         public List<String> getData() {
             return datas;
         }
 
         @Override
         public int getCount() {
             return datas.size();
         }
 
         @Override
         public Object getItem( int position) {
             return datas.get(position);
         }
 
         @Override
         public long getItemId( int position) {
             return position;
         }
 
         @Override
         public View getView( int position, View convertView, ViewGroup parent) {
             if (convertView == null ) {
                 convertView = MainActivity. this .getLayoutInflater().inflate(R.layout.item, null );
             }
 
             TextView tv = (TextView) convertView.findViewById(R.id.text);
             tv.setText(datas.get(position));
 
             return convertView;
         }
     }
}

listView_footer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<? xml version="1.0" encoding="utf-8"?>
< RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:background="@color/very_light_gray"
     android:gravity="center"
     android:layout_gravity="center_horizontal"
     android:paddingBottom="10dip"
     android:paddingTop="10dip" >
 
     < ProgressBar
         android:id="@+id/pull_to_refresh_load_progress"
         style="@android:style/Widget.ProgressBar.Small.Inverse"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_centerHorizontal="true"
         android:layout_centerVertical="true"
         android:indeterminate="true"
         android:paddingRight="10dp" />
 
     < TextView
         android:id="@+id/pull_to_refresh_loadmore_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:gravity="center_vertical"
         android:layout_toRightOf="@+id/pull_to_refresh_load_progress"
         android:paddingTop="5dip"
         android:text="@string/loading"
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:textColor="@android:color/darker_gray"
         android:textSize="14sp"
         android:textStyle="bold" />
 
</ RelativeLayout >

main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<? xml version="1.0" encoding="utf-8"?>
< com.example.demo.mySwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/swipe_layout"
     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 >
 
</ com.example.demo.mySwipeRefreshLayout >

item.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<? 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="match_parent"
     android:orientation="vertical" >
 
     < TextView
         android:id="@+id/text"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="left"
         android:padding="10dp"
         android:text="wo lai le"
         android:background="@color/very_light_gray"/>
     
     < View
         android:layout_width="match_parent"
         android:layout_height="1dp"
         android:background="@android:color/white"/>
 
</ LinearLayout >

 

参考链接

http://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html

 

版权所有,转载须注明作者(金田)及出处(原文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值