【问题标题】:How to implement "Swipe down to refresh" like in new GMail app如何在新的 GMail 应用程序中实现“向下滑动刷新”
【发布时间】:2013-06-06 10:13:33
【问题描述】:

Google 发布了新的 Gmail 应用程序,它提供了一种处理下拉刷新的替代方式。

而不是显示被拉下的开始隐藏行。 Gmail 在操作栏上方显示一条动画消息。

消息包含一条动画水平线。

这是 Android SDK 的标准功能吗?我在操作栏 API 中找不到任何可以执行此操作的内容。

【问题讨论】:

标签: android android-listview pull-to-refresh


【解决方案1】:

Google 已直接在 SDK 中发布了对此的支持。我不确定您需要支持哪个版本(这可能是个问题)。

在此处查看官方 SDK 功能信息:http://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html

如果你能使用 SDK 的话,你会过得更好,甚至 Chris Banes 也写了一个post,也是这么建议的。

【讨论】:

  • 太棒了。感谢您抽出宝贵时间添加此答案。
  • 不幸的是,SwipeRefreshLayout 的实现无法在不同刷新状态的 ActionBar 叠加层中显示自定义消息。 ProgressBar 也显示在 ActionBar 下方而不是内部(例如,在 Google+ 应用中)。
【解决方案2】:

Chris Banes' ActionBar-PullToRefresh library on GitHub 可能提供最接近 GMail 应用程序的下拉刷新功能。

另请参阅:Juhani Lehtimäki's analysis of GMail pull-to-refresh

【讨论】:

  • Chris Banes 的 ActionBar-PullToRefresh 库不再维护?有什么选择吗?
  • @AnhSirkDasarp 你可能指的是他的 Android-PullToRefresh。这个 (ActionBar-PullToRefresh) 是一个替代方案。
  • 哦..好的..谢谢@laalto
  • gmail 中的拉动刷新已更改,请参阅:antonioleiva.com/swiperefreshlayout
【解决方案3】:

试试这个……它对我有用。

res/layout/activity_main.xml

 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.swipetorefresh.MainActivity"
tools:ignore="MergeRootFrame" />

res/layout/fragment_main.xml

<android.support.v4.widget.SwipeRefreshLayout           
       xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:id="@+id/container"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
       tools:ignore="MergeRootFrame" >

   <ListView
      android:id="@android:id/list"
      android:layout_width="match_parent"
      android:layout_height="match_parent" />

</android.support.v4.widget.SwipeRefreshLayout>

MainActivity.java

  public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (savedInstanceState == null) {
        getFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment()).commit();
    }
}

public static class PlaceholderFragment extends ListFragment implements OnRefreshListener {

    private SwipeRefreshLayout mSwipeRefreshLayout;

    private static final int LIST_ITEM_COUNT = 5;
    private int mOffset = 0;

    private ArrayAdapter<String> mListAdapter;

    public PlaceholderFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container,
                false);

        // Configure the swipe refresh layout
        mSwipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.container);
        mSwipeRefreshLayout.setOnRefreshListener(this);
        mSwipeRefreshLayout.setColorScheme(
                R.color.swipe_color_1, R.color.swipe_color_2,
                R.color.swipe_color_3, R.color.swipe_color_4);

        // Put the first batch of countries in the list
        mListAdapter = new ArrayAdapter<String>(
                getActivity(),
                android.R.layout.simple_list_item_1,
                android.R.id.text1,
                getCountries(mOffset));

        setListAdapter(mListAdapter);

        return rootView;
    }

    private List<String> getCountries(int offset) {
        ArrayList<String> countriesList = new ArrayList<String>();
        for(int i=0; i<LIST_ITEM_COUNT;i++){
            countriesList.add(COUNTRIES[offset+i]);
        }

        mOffset = offset + LIST_ITEM_COUNT;
        return countriesList;
    }

    @Override
    public void onRefresh() {
        // Start showing the refresh animation
        mSwipeRefreshLayout.setRefreshing(true);

        // Simulate a long running activity
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
               updateCountries();
            }
        }, 5000);
    }



    private void updateCountries() {

        // Add the next batch of countries to the list
        mListAdapter.addAll(getCountries(mOffset));

        // Signify that we are done refreshing
        mSwipeRefreshLayout.setRefreshing(false);
    }



    private static final String[] COUNTRIES = {"Afghanistan",
        "Albania", "Algeria", "American Samoa", "Andorra", "Angola",
        "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
        "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
        "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus",
        "Belgium", "Belize", "Benin", "Bermuda", "Bhutan",
        "Bolivia", "Bosnia and Herzegovina", "Botswana", "Brazil",
        "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi",
        "Cambodia", "Cameroon", "Canada", "Cape Verde", "Cayman Islands",
        "Central African Republic", "Chad", "Chile", "China",
        "Christmas Island", "Cocos (Keeling) Islands", "Colombia",
        "Comoros", "Democratic Republic of the Congo (Kinshasa)",
        "Congo, Republic of(Brazzaville)", "Cook Islands", "Costa Rica",
        "Ivory Coast", "Croatia", "Cuba", "Cyprus", "Czech Republic",
        "Denmark", "Djibouti", "Dominica", "Dominican Republic",
        "East Timor (Timor-Leste)", "Ecuador", "Egypt",
        "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia"};

        }
   }

【讨论】:

    【解决方案4】:

    Chris Banes(为 android 实现了最佳 pull to refresh 组件的同一个人)也实现了 Gmail,例如 Pull To Refresh。

    你可以在这里找到它:https://github.com/chrisbanes/ActionBar-PullToRefresh

    请注意,此项目仍在开发中,因此当前 API 可能会更改。

    【讨论】:

      【解决方案5】:
      fragment_main.xml
      
      <RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
          android:paddingLeft="@dimen/activity_horizontal_margin"
          android:paddingRight="@dimen/activity_horizontal_margin"
          android:paddingTop="@dimen/activity_vertical_margin"
          tools:context="com.example.testloading.MainActivity$PlaceholderFragment" >
      
        <ListView
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
      
      </RelativeLayout>    
      
      
      counteries.xml
      
      <?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_view"
              android:layout_width="match_parent"
              android:layout_height="47dp"
              android:gravity="center_vertical"
              android:textStyle="bold"/>
      </LinearLayout>
      
      
      
      package com.example.testloading;
      
      import java.util.ArrayList;
      import java.util.List;
      
      import android.content.Context;
      import android.os.Bundle;
      import android.support.v4.app.Fragment;
      import android.support.v7.app.ActionBarActivity;
      import android.util.Log;
      import android.view.LayoutInflater;
      import android.view.Menu;
      import android.view.MenuItem;
      import android.view.View;
      import android.view.ViewGroup;
      import android.widget.AbsListView;
      import android.widget.AbsListView.OnScrollListener;
      import android.widget.BaseAdapter;
      import android.widget.ListView;
      import android.widget.TextView;
      
      public class MainActivity extends ActionBarActivity {
      
          private static final String TAG = MainActivity.class.getSimpleName();
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              if (savedInstanceState == null) {
                  getSupportFragmentManager().beginTransaction()
                          .add(R.id.container, new PlaceholderFragment()).commit();
              }
          }
      
          @Override
          public boolean onCreateOptionsMenu(Menu menu) {
      
              // Inflate the menu; this adds items to the action bar if it is present.
              getMenuInflater().inflate(R.menu.main, menu);
              return true;
          }
      
          @Override
          public boolean onOptionsItemSelected(MenuItem item) {
              // Handle action bar item clicks here. The action bar will
              // automatically handle clicks on the Home/Up button, so long
              // as you specify a parent activity in AndroidManifest.xml.
              int id = item.getItemId();
              if (id == R.id.action_settings) {
                  return true;
              }
              return super.onOptionsItemSelected(item);
          }
      
          /**
           * A placeholder fragment containing a simple view.
           */
          public static class PlaceholderFragment extends Fragment {
      
              private ListView listView;
              private static final int LIST_ITEM_COUNT = 20;
              private int mOffset = 0;
              private boolean flag_loading;
      
              private MyAdapter adapter;
              private List<String> list;
      
              public PlaceholderFragment() {
              }
      
              @Override
              public View onCreateView(LayoutInflater inflater, ViewGroup container,
                      Bundle savedInstanceState) {
                  View rootView = inflater.inflate(R.layout.fragment_main, container,
                          false);
      
                  listView = (ListView) rootView.findViewById(R.id.list);
                  list = getCountries(mOffset);
                  adapter = new MyAdapter(list, getActivity());
                  listView.setAdapter(adapter);
                  listView.setOnScrollListener(new OnScrollListener() {
      
                      @Override
                      public void onScrollStateChanged(AbsListView view,
                              int scrollState) {
                      }
      
                      @Override
                      public void onScroll(AbsListView view, int firstVisibleItem,
                              int visibleItemCount, int totalItemCount) {
                          Log.d(TAG, "firstVisibleItem : " + firstVisibleItem
                                  + " , visibleItemCount : " + visibleItemCount
                                  + " , totalItemCount : " + totalItemCount);
                          if (firstVisibleItem + visibleItemCount == totalItemCount) {
                              Log.d(TAG, "ZZZ offSet : " + mOffset);
                              if (COUNTRIES.length > mOffset) {
                                  if (flag_loading == false) {
                                      Log.d(TAG, "ZZZ inside : ");
                                      flag_loading = true;
                                      additems();
                                  }
                              }
                          }
      
                      }
                  });
                  return rootView;
              }
      
              protected void additems() {
                  list.addAll(getCountries(mOffset));
                  adapter.notifyDataSetChanged();
                  listView.invalidate();
                  flag_loading = false;
              }
      
              private List<String> getCountries(int offset) {
                  ArrayList<String> countriesList = new ArrayList<String>();
                  for (int i = 0; i < LIST_ITEM_COUNT; i++) {
                      if (COUNTRIES.length > offset + i) {
                          countriesList.add(COUNTRIES[offset + i]);
                      }
                  }
      
                  mOffset = offset + LIST_ITEM_COUNT;
                  return countriesList;
              }
      
              private static final String[] COUNTRIES = { "Afghanistan", "Albania",
                      "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla",
                      "Antarctica", "Antigua and Barbuda", "Argentina", "Armenia",
                      "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas",
                      "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
                      "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
                      "Bosnia and Herzegovina", "Botswana", "Brazil",
                      "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi",
                      "Cambodia", "Cameroon", "Canada", "Cape Verde",
                      "Cayman Islands", "Central African Republic", "Chad", "Chile",
                      "China", "Christmas Island", "Cocos (Keeling) Islands",
                      "Colombia", "Comoros",
                      "Democratic Republic of the Congo (Kinshasa)",
                      "Congo, Republic of(Brazzaville)", "Cook Islands",
                      "Costa Rica", "Ivory Coast", "Croatia", "Cuba", "Cyprus",
                      "Czech Republic", "Denmark", "Djibouti", "Dominica",
                      "Dominican Republic", "East Timor (Timor-Leste)", "Ecuador",
                      "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
                      "Estonia", "Ethiopia" };
      
          }
      }
      
      class MyAdapter extends BaseAdapter {
      
          private List<String> list;
          private LayoutInflater layoutInflater;
      
          public MyAdapter(List<String> list, Context context) {
              this.list = list;
              layoutInflater = (LayoutInflater) context
                      .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
          }
      
          @Override
          public int getCount() {
              return list.size();
          }
      
          @Override
          public Object getItem(int position) {
              return list.get(position);
          }
      
          @Override
          public long getItemId(int arg0) {
              // TODO Auto-generated method stub
              return 0;
          }
      
          @Override
          public View getView(int position, View convertView, ViewGroup arg2) {
      
              ViewHolder viewHolder;
      
              if (convertView == null) {
                  convertView = layoutInflater.inflate(R.layout.counteries, null);
                  viewHolder = new ViewHolder();
                  viewHolder.textView = (TextView) convertView
                          .findViewById(R.id.text_view);
                  convertView.setTag(viewHolder);
              } else {
                  viewHolder = (ViewHolder) convertView.getTag();
              }
      
              viewHolder.textView.setText(list.get(position));
              return convertView;
          }
      
          class ViewHolder {
              public TextView textView;
          }
      }
      

      【讨论】:

        【解决方案6】:

        测试一下。 使用: swipeRefreshLayout.setRotation(180f);

        在你的适配器 ListView 中,getView 方法: view.setRotation(180f);

        反转列表中项目的顺序。

        或者直接在xml中使用android:rotation="180"。

        【讨论】:

          猜你喜欢
          • 2022-12-22
          • 2015-01-04
          • 1970-01-01
          • 1970-01-01
          • 2016-06-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多