1
/*
2
* Copyright 2014 The Android Open Source Project
3
*
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
7
*
8
* http://www.apache.org/licenses/LICENSE-2.0
9
*
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
15
*/
16
17
package com.example.android.swiperefreshlistfragment;
18
19
import android.content.Context;
20
import android.os.Bundle;
21
import android.support.v4.app.ListFragment;
22
import android.support.v4.view.ViewCompat;
23
import android.support.v4.widget.SwipeRefreshLayout;
24
import android.view.LayoutInflater;
25
import android.view.View;
26
import android.view.ViewGroup;
27
import android.widget.ListView;
28
29
/**
30
* Subclass of {@link android.support.v4.app.ListFragment} which provides automatic support for
31
* providing the 'swipe-to-refresh' UX gesture by wrapping the the content view in a
32
* {@link android.support.v4.widget.SwipeRefreshLayout}.
33
*/
34
public class SwipeRefreshListFragment extends ListFragment {
35
36
private SwipeRefreshLayout mSwipeRefreshLayout;
37
38
@Override
39
public View onCreateView(LayoutInflater inflater, ViewGroup container,
40
Bundle savedInstanceState) {
41
42
// Create the list fragment's content view by calling the super method
43
final View listFragmentView = super.onCreateView(inflater, container, savedInstanceState);
44
45
// Now create a SwipeRefreshLayout to wrap the fragment's content view
46
mSwipeRefreshLayout = new ListFragmentSwipeRefreshLayout(container.getContext());
47
48
// Add the list fragment's content view to the SwipeRefreshLayout, making sure that it fills
49
// the SwipeRefreshLayout
50
mSwipeRefreshLayout.addView(listFragmentView,
51
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
52
53
// Make sure that the SwipeRefreshLayout will fill the fragment
54
mSwipeRefreshLayout.setLayoutParams(
55
new ViewGroup.LayoutParams(
56
ViewGroup.LayoutParams.MATCH_PARENT,
57
ViewGroup.LayoutParams.MATCH_PARENT));
58
59
// Now return the SwipeRefreshLayout as this fragment's content view
60
return mSwipeRefreshLayout;
61
}
62
63
/**
64
* Set the {@link android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener} to listen for
65
* initiated refreshes.
66
*
67
* @see android.support.v4.widget.SwipeRefreshLayout#setOnRefreshListener(android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener)
68
*/
69
public void setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener listener) {
70
mSwipeRefreshLayout.setOnRefreshListener(listener);
71
}
72
73
/**
74
* Returns whether the {@link android.support.v4.widget.SwipeRefreshLayout} is currently
75
* refreshing or not.
76
*
77
* @see android.support.v4.widget.SwipeRefreshLayout#isRefreshing()
78
*/
79
public boolean isRefreshing() {
80
return mSwipeRefreshLayout.isRefreshing();
81
}
82
83
/**
84
* Set whether the {@link android.support.v4.widget.SwipeRefreshLayout} should be displaying
85
* that it is refreshing or not.
86
*
87
* @see android.support.v4.widget.SwipeRefreshLayout#setRefreshing(boolean)
88
*/
89
public void setRefreshing(boolean refreshing) {
90
mSwipeRefreshLayout.setRefreshing(refreshing);
91
}
92
93
/**
94
* Set the color scheme for the {@link android.support.v4.widget.SwipeRefreshLayout}.
95
*
96
* @see android.support.v4.widget.SwipeRefreshLayout#setColorScheme(int, int, int, int)
97
*/
98
public void setColorScheme(int colorRes1, int colorRes2, int colorRes3, int colorRes4) {
99
mSwipeRefreshLayout.setColorScheme(colorRes1, colorRes2, colorRes3, colorRes4);
100
}
101
102
/**
103
* @return the fragment's {@link android.support.v4.widget.SwipeRefreshLayout} widget.
104
*/
105
public SwipeRefreshLayout getSwipeRefreshLayout() {
106
return mSwipeRefreshLayout;
107
}
108
109
/**
110
* Sub-class of {@link android.support.v4.widget.SwipeRefreshLayout} for use in this
111
* {@link android.support.v4.app.ListFragment}. The reason that this is needed is because
112
* {@link android.support.v4.widget.SwipeRefreshLayout} only supports a single child, which it
113
* expects to be the one which triggers refreshes. In our case the layout's child is the content
114
* view returned from
115
* {@link android.support.v4.app.ListFragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)}
116
* which is a {@link android.view.ViewGroup}.
117
*
118
* <p>To enable 'swipe-to-refresh' support via the {@link android.widget.ListView} we need to
119
* override the default behavior and properly signal when a gesture is possible. This is done by
120
* overriding {@link #canChildScrollUp()}.
121
*/
122
private class ListFragmentSwipeRefreshLayout extends SwipeRefreshLayout {
123
124
public ListFragmentSwipeRefreshLayout(Context context) {
125
super(context);
126
}
127
128
/**
129
* As mentioned above, we need to override this method to properly signal when a
130
* 'swipe-to-refresh' is possible.
131
*
132
* @return true if the {@link android.widget.ListView} is visible and can scroll up.
133
*/
134
@Override
135
public boolean canChildScrollUp() {
136
final ListView listView = getListView();
137
if (listView.getVisibility() == View.VISIBLE) {
138
return canListViewScrollUp(listView);
139
} else {
140
return false;
141
}
142
}
143
144
}
145
147
/**
148
* Utility method to check whether a {@link ListView} can scroll up from it's current position.
149
* Handles platform version differences, providing backwards compatible functionality where
150
* needed.
151
*/
152
private static boolean canListViewScrollUp(ListView listView) {
153
if (android.os.Build.VERSION.SDK_INT >= 14) {
154
// For ICS and above we can call canScrollVertically() to determine this
155
return ViewCompat.canScrollVertically(listView, -1);
156
} else {
157
// Pre-ICS we need to manually check the first visible item and the child view's top
158
// value
159
return listView.getChildCount() > 0 &&
160
(listView.getFirstVisiblePosition() > 0
161
|| listView.getChildAt(0).getTop() < listView.getPaddingTop());
162
}
163
}
165
166
}