469

在 Twitter(官方应用)等 Android 应用程序中,当遇到 ListView 时,可以将其拉下(释放时会弹回)以刷新内容。

我想知道在您看来,实现它的最佳方式是什么?

我能想到的一些可能性:

  1. ListView 顶部的一个项目 - 但是我认为使用 ListView 上的动画滚动回项目位置 1(基于 0)并不是一件容易的事。
  2. ListView 之外的另一个视图 - 但我需要注意在拉动 ListView 时将其位置向下移动,而且我不确定我们是否可以检测到对 ListView 的拖动触摸是否仍然真的滚动 ListView 上的项目。

有什么建议吗?

PS我想知道官方Twitter应用程序源代码何时发布。已经提到它会发布,但是6个月过去了,从那以后我们就没有听说过它。

4

16 回答 16

367

终于,谷歌发布了正式版的pull-to-refresh库!

SwipeRefreshLayout在支持库中被调用,文档在这里

  1. 添加SwipeRefreshLayout为视图的父视图,这将被视为刷新布局的拉动。(我ListView举个例子,它可以是任何ViewlikeLinearLayoutScrollView

     <android.support.v4.widget.SwipeRefreshLayout
         android:id="@+id/pullToRefresh"
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
         <ListView
             android:id="@+id/listView"
             android:layout_width="match_parent"
             android:layout_height="match_parent"/>
     </android.support.v4.widget.SwipeRefreshLayout>
    
  2. 为您的班级添加一个监听器

     protected void onCreate(Bundle savedInstanceState) {
         final SwipeRefreshLayout pullToRefresh = findViewById(R.id.pullToRefresh);
         pullToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
             @Override
             public void onRefresh() {
                 refreshData(); // your code
                 pullToRefresh.setRefreshing(false);
             }
         });
     }
    

您也可以pullToRefresh.setRefreshing(true/false);根据您的要求拨打电话。

更新

Android 支持库已被弃用,并已被 AndroidX 取代。可以在此处找到新库的链接。

此外,您需要将以下依赖项添加到您的项目中:

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'

或者

你可以去 Refactor>>Migrate to AndroidX 和 Android Studio 会为你处理依赖。

于 2014-04-01T13:06:56.590 回答
80

我已经尝试实现一个拉动刷新组件,它远未完成,但演示了一个可能的实现,https://github.com/johannilsson/android-pulltorefresh

主要逻辑是在PullToRefreshListViewextends中实现的ListView在内部,它使用(API 级别 8)控制标题视图的滚动。smoothScrollBy该小部件现已更新,支持 1.5 及更高版本,但请阅读 README 以获得 1.5 支持。

在您的布局中,您只需像这样添加它。

<com.markupartist.android.widget.PullToRefreshListView
    android:id="@+id/android:list"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
    />
于 2011-01-11T08:02:22.500 回答
55

我还为 Android 实现了一个强大的、开源的、易于使用且高度可定制的 PullToRefresh 库。您可以按照项目页面上的文档中的说明将 ListView 替换为 PullToRefreshListView。

https://github.com/erikwt/PullToRefresh-ListView

于 2012-01-07T02:03:24.933 回答
42

我认为最简单的方法是由 android 支持库提供:

android.support.v4.widget.SwipeRefreshLayout;

导入后,您可以将布局定义如下:

  <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/refresh"
        android:layout_height="match_parent"
        android:layout_width="match_parent">
    <android.support.v7.widget.RecyclerView
        xmlns:recycler_view="http://schemas.android.com/apk/res-auto"
        android:id="@android:id/list"
        android:theme="@style/Theme.AppCompat.Light"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/button_material_light"
        >

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

我假设您使用回收站视图而不是列表视图。但是,listview 仍然有效,因此您只需将 recyclerview 替换为 listview 并更新 java 代码(片段)中的引用。

在您的活动片段中,您首先实现接口SwipeRefreshLayout.OnRefreshListener:i,e

public class MySwipeFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener{
private SwipeRefreshLayout swipeRefreshLayout;

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_item, container, false);
        swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.refresh);
        swipeRefreshLayout.setOnRefreshListener(this);
}


 @Override
  public void onRefresh(){
     swipeRefreshLayout.setRefreshing(true);
     refreshList();
  }
  refreshList(){
    //do processing to get new data and set your listview's adapter, maybe  reinitialise the loaders you may be using or so
   //when your data has finished loading, cset the refresh state of the view to false
   swipeRefreshLayout.setRefreshing(false);

   }
}

希望对大众有所帮助

于 2015-06-15T18:28:08.910 回答
23

在此链接中,您可以找到著名视图的一个分支,PullToRefresh它具有新的有趣实现,例如PullTorRefreshWebViewor或在列表底部边缘PullToRefreshGridView添加 a 的可能性。PullToRefresh

https://github.com/chrisbanes/Android-PullToRefresh

最好的是在 Android 4.1 中完美运行(正常PullToRefresh不起作用)

于 2012-06-14T10:11:18.203 回答
19

要实现 android Pull-to-Refresh 试试这段代码,

<android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/pullToRefresh"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

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

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

活动类:

ListView lv = (ListView) findViewById(R.id.lv);
SwipeRefreshLayout pullToRefresh = (SwipeRefreshLayout) findViewById(R.id.pullToRefresh);


lv.setAdapter(mAdapter);

pullToRefresh.setOnRefreshListener(new OnRefreshListener() {

        @Override
        public void onRefresh() {
            // TODO Auto-generated method stub

            refreshContent();

        }
    });



private void refreshContent(){ 

     new Handler().postDelayed(new Runnable() {
            @Override public void run() {
                pullToRefresh.setRefreshing(false);
            }
        }, 5000);

 }
于 2015-05-20T08:51:10.633 回答
18

我有非常简单的方法来做到这一点,但现在确定它是万无一失的方法有我的代码 PullDownListView.java

package com.myproject.widgets;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;

/**
 * @author Pushpan
 * @date Nov 27, 2012
 **/
public class PullDownListView extends ListView implements OnScrollListener {

    private ListViewTouchEventListener mTouchListener;
    private boolean pulledDown;

    public PullDownListView(Context context) {
        super(context);
        init();
    }

    public PullDownListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PullDownListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        setOnScrollListener(this);
    }

    private float lastY;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            lastY = ev.getRawY();
        } else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
            float newY = ev.getRawY();
            setPulledDown((newY - lastY) > 0);
            postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (isPulledDown()) {
                        if (mTouchListener != null) {
                            mTouchListener.onListViewPulledDown();
                            setPulledDown(false);
                        }
                    }
                }
            }, 400);
            lastY = newY;
        } else if (ev.getAction() == MotionEvent.ACTION_UP) {
            lastY = 0;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        setPulledDown(false);
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }

    public interface ListViewTouchEventListener {
        public void onListViewPulledDown();
    }

    public void setListViewTouchListener(
            ListViewTouchEventListener touchListener) {
        this.mTouchListener = touchListener;
    }

    public ListViewTouchEventListener getListViewTouchListener() {
        return mTouchListener;
    }

    public boolean isPulledDown() {
        return pulledDown;
    }

    public void setPulledDown(boolean pulledDown) {
        this.pulledDown = pulledDown;
    }
}

您只需要在要使用此 ListView 的活动上实现 ListViewTouchEventListener 并设置侦听器

我在 PullDownListViewActivity 中实现了它

package com.myproject.activities;

import android.app.Activity;
import android.os.Bundle;

/**
 * @author Pushpan
 *
 */
public class PullDownListViewActivity extends Activity implements ListViewTouchEventListener {

    private PullDownListView listView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        listView = new PullDownListView(this);
        setContentView(listView);
        listView.setListViewTouchListener(this);

        //setItems in listview
    }

    public void onListViewPulledDown(){
        Log.("PullDownListViewActivity", "ListView pulled down");
    }
}

这个对我有用 :)

于 2012-11-27T11:45:02.820 回答
10

没有人提到像 Google Now 或 Gmail 应用程序那样显示在操作栏顶部的新型“拉动刷新”。

有一个库ActionBar-PullToRefresh的工作原理完全相同。

于 2013-12-21T11:10:31.497 回答
7

请注意,在 Android 和 WP 上实施时需要解决 UX 问题。

“为什么设计师/开发人员不应该以 iOS 应用程序的方式实现下拉刷新的一个很好的指标是,谷歌和他们的团队从不在 Android 上使用下拉刷新,而在 iOS 中使用它。”

https://plus.google.com/109453683460749241197/posts/eqYxXR8L4eb

于 2012-11-01T20:12:02.210 回答
4

如果您不希望您的程序看起来像强制安装到 Android 中的 iPhone 程序,请瞄准更原生的外观和感觉并执行类似于 Gingerbread 的操作:

替代文字

于 2011-01-05T14:34:28.440 回答
4

我在这里写了一个拉刷新组件:https ://github.com/guillep/PullToRefresh 如果列表没有项目,它会起作用,并且我已经在> = 1.6 android手机上对其进行了测试。

任何建议或改进表示赞赏:)

于 2011-07-30T20:05:21.840 回答
2

我认为最好的库是:https ://github.com/chrisbanes/Android-PullToRefresh 。

适用于:

ListView
ExpandableListView
GridView
WebView
ScrollView
HorizontalScrollView
ViewPager
于 2014-05-25T05:13:24.107 回答
2

我们首先要知道 android 中的 Pull to refresh layout 是什么。我们可以在 android 中调用 pull 来刷新为 swipe-to-refresh。当您从上到下滑动屏幕时,它会根据 setOnRefreshListener 执行一些操作。

这是演示如何实现 android pull to refresh的教程。我希望这有帮助。

于 2019-09-04T08:22:09.673 回答
1

要获得最新的 Lollipop Pull-To Refresh:

  1. 下载最新的 Lollipop SDK 和 Extras/Android 支持库
  2. 将项目的构建目标设置为 Android 5.0(否则支持包可能会出现资源错误)
  3. 将您的 libs/android-support-v4.jar 更新到第 21 个版本
  4. 使用android.support.v4.widget.SwipeRefreshLayout加号android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener

详细指南可以在这里找到:http: //antonioleiva.com/swiperefreshlayout/

加上我建议在评论中阅读的 ListView canChildScrollUp();)

于 2014-11-19T20:34:45.440 回答
1

Yalantis非常有趣的Pull-to-Refresh。适用于 iOS 的 Gif,但您可以检查它:)

<com.yalantis.pulltorefresh.library.PullToRefreshView
android:id="@+id/pull_to_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
    android:id="@+id/list_view"
    android:divider="@null"
    android:dividerHeight="0dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

于 2015-01-19T13:42:39.987 回答
1

那些希望为RecyclerView实现拉取刷新功能的人可以按照我的简单教程如何在 Android 中为 RecyclerView 实现拉取刷新

要导入的库

implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0'

XML 代码

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    android:id="@+id/swipe_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

活动JAVA代码

import androidx.appcompat.app.AppCompatActivity;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.os.Bundle;
import android.os.Handler;

public class MainActivity extends AppCompatActivity {

private SwipeRefreshLayout swipeRefreshLayout;

...

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        ...
        swipeRefreshLayout = findViewById(R.id.swipe_layout);
        initializeRefreshListener();
}

    void initializeRefreshListener() {

        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                // This method gets called when user pull for refresh,
                // You can make your API call here,
                // We are using adding a delay for the moment
                final Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if(swipeRefreshLayout.isRefreshing()) {
                            swipeRefreshLayout.setRefreshing(false);
                        }
                    }
                }, 3000);
            }
        });
    }
于 2020-10-11T07:00:22.507 回答