SwipeRefreshListFragment / src / com.example.android.swiperefreshlistfragment /

SwipeRefreshListFragment.java

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
}