ChatGPT解决这个技术问题 Extra ChatGPT

如何实现Android Pull-to-Refresh

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

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

我能想到的一些可能性:

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

有什么建议吗?

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

这个功能是否可以在动态创建的 TableLayout 中实现。请帮忙.....
github.com/fruitranger/PulltorefreshListView 是我的另一个实现。流畅的多点触控支持。
相关:“Pull-to-refresh”: an anti UI pattern on Android 是一篇文章,认为此 UI 应该在 Android 上使用,并引发了很多关于其适用性的讨论。
有人应该让 Google 知道,因为最新版本的 Android 版 Gmail 使用了这种“反模式”。
拉动刷新是(并且已经有一段时间了)iOS 和 Android 中采用的标准模式,它非常自然,所以这种反模式讨论已经过时了。用户会期望看到它并表现得如此。

M
MSpeed

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

它在支持库中称为 SwipeRefreshLayout,文档为 here

添加 SwipeRefreshLayout 作为视图的父级,这将被视为刷新布局的拉动。 (我以 ListView 为例,它可以是任何 View,如 LinearLayout、ScrollView 等) 添加监听到你的类 protected void onCreate(Bundle savedInstanceState) { final SwipeRefreshLayout pullToRefresh = findViewById(R.id.pullToRefresh); pullToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { refreshData(); // 你的代码 pullToRefresh.setRefreshing(false); } }); }

您也可以根据需要调用 pullToRefresh.setRefreshing(true/false);

更新

Android 支持库已被弃用,并已被 AndroidX 取代。可以找到指向新库的链接 here

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

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'

或者

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


我可以在 SwipeRefreshLayout 上使用 ProgressBar 而不是配色方案吗?
2014 年 4 月 1 日 - 这不是开玩笑
J
Johan Berg Nilsson

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

主要逻辑在扩展 ListViewPullToRefreshListView 中实现。 在内部,它使用 smoothScrollBy(API 级别 8)控制标题视图的滚动。 小部件现已更新,支持 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"
    />

嗨约翰,我已经下载了你的示例代码。它适用于 android 2.2 设备,但不适用于 2.1 设备。我认为因为它使用了仅在 2.2 或更高版本中可用的 smoothScrollBy 方法,对吗?你有什么想法将这个效果实现到 2.1 或更早版本中吗?谢谢
是的,正如我在回答 smoothScrollBy 在 API 级别 8 (2.2) 中引入的那样,这是正确的。我还没有想出一个为其他版本实现它的正确方法,但它猜测应该可以移植 smoothScrollBy 的实现,但我想讨论应该保留在项目站点而不是堆栈溢出?
id 是@+id/android:list 而不是@android:id/list 是不是故意的,看起来很奇怪?该项目在我这边引发了通货膨胀错误,我目前正在检查...
这是我发现的最好的拉刷新库..github.com/chrisbanes/Android-PullToRefresh。它适用于 ListViews、GridViews 和 Webviews。还实现了上拉刷新模式。
在使用 Intellij Idea 时如何将项目添加到库文件夹中?有谁能够帮我?
E
Erik

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

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


我尝试了这里列出的所有实现,而你的实现是最好的,就简单/纯/平滑的拉动刷新实现而言(没有点击刷新像 Johan 那样的怪异)。谢谢!
这可以替换标准 ListView 以与 ListActivity、ListFragment 等一起使用吗?
是的,只需为 PullToRefreshListView 提供正确的 ID。在 XML 中:android:id="@android:id/list"
这真是太棒了!谷歌把我带到了这里,通过这些例子,你的看起来最容易实现。太棒了,谢谢你,先生!
非常明智的设计组件,美观而简单。这绝对应该是公认的答案。
A
Akah

我认为最简单的方法是由 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:即

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);

   }
}

希望对大众有所帮助


它运作良好。但是,关于 setRefreshing 的一件事:如 developer.android.com/reference/android/support/v4/widget/… 中所述,“当通过滑动手势触发刷新时不要调用它”
A
Aracem

在此链接中,您可以找到著名的 PullToRefresh 视图的分支,该视图具有新的有趣实现,例如 PullTorRefreshWebViewPullToRefreshGridView,或者可以在列表的底部边缘添加 PullToRefresh

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

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


自述文件顶部的一个重要注释表明:该项目不再被维护。无论如何,这个库是我迄今为止见过的最好的库!做得好!
仅仅因为它不再被维护,并不意味着它不好。仍然使用它来满足我所有的刷新需求:)
m
mani

要实现 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);

 }

P
Pushpan

我有非常简单的方法来做到这一点,但现在确定它是万无一失的方法有我的代码 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");
    }
}

这个对我有用 :)


t
tomrozb

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

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


Q
QED

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

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

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


我知道这已经有一年多了,但 Gmail 应用程序确实使用下拉刷新。但是在 UI 方面并不完全相同,列表不会向下滚动,而是在屏幕顶部显示一个新视图。
L
Lie Ryan

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

https://i.stack.imgur.com/SPejA.png


@Rob:我的意思是当你过度拉动时列表顶部有橙色阴影,而不是像 iPhone 上那样让列表反弹。这意味着作为评论(不是回答),但评论不能有图像。
啊,对不起,好主意。我还没有玩过姜饼,所以还没有看到效果。仍在等待谷歌将其推出到 nexus 之一。
我有姜饼,当列表是静态的时,橙色发光效果很好。但是下拉刷新是刷新动态列表的一个很好的 UI 机制。虽然它在 iOS 世界中很流行,但它是一种在 Android 生态系统中并不奇怪的 UI 技巧。我强烈建议您在官方 Twitter 应用程序中查看。 :)
此处的本机行为是指示您已到达列表的末尾。接受这一点并执行刷新同样是非本地的,因为您没有做平台所做的事情。这意味着您更有可能让用户感到惊讶。我当然不会因为我到达列表的末尾而期望也不想刷新。下拉刷新更加直观和清晰。由于原生 twitter 应用程序使用它,我认为可以公平地说这是一个很多人都熟悉的 UI 概念。
G
Guille Polito

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

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


J
Jossy Paul

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

适用于:

ListView
ExpandableListView
GridView
WebView
ScrollView
HorizontalScrollView
ViewPager

H
Hasan Raza

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

这里的 tutorial 演示了如何实现 android pull to refresh。我希望这有帮助。


g
goRGon

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

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

可在此处找到详细指南:http://antonioleiva.com/swiperefreshlayout/

对于 ListView,我建议在评论中阅读有关 canChildScrollUp() 的信息;)


加上一个只是为了提到 canChildScrollUp()。很重要!
e
edbaev

YalantisPull-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" />


A
Asad Ali Choudhry

那些希望为 RecyclerView 实现拉取刷新功能的人可以按照我的简单教程How to implement Pull To Refresh for RecyclerView in Android进行操作。

要导入的库

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);
            }
        });
    }

A
Ahsan Malik

在你的布局中添加这个

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

现在只需在您的代码中添加以下这些行

 mSwipeRefreshLayout.setOnRefreshListener(() -> {

       // your refresh code here

    });

你都完成了