Home | History | Annotate | Download | only in swiperefreshlistfragment
      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 
    146     // BEGIN_INCLUDE (check_list_can_scroll)
    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     }
    164     // END_INCLUDE (check_list_can_scroll)
    165 
    166 }
    167