Cách triển khai Android Pull-to-Refresh


433

Trong các ứng dụng Android như Twitter (ứng dụng chính thức), khi bạn gặp ListView, bạn có thể kéo nó xuống (và nó sẽ bật lại khi được phát hành) để làm mới nội dung.

Tôi tự hỏi đâu là cách tốt nhất, theo ý kiến ​​của bạn, để thực hiện điều đó?

Một số khả năng tôi có thể nghĩ ra:

  1. Một mục ở trên ListView - tuy nhiên tôi không nghĩ việc cuộn trở lại vị trí mục 1 (dựa trên 0) với hình ảnh động trên ListView là một nhiệm vụ dễ dàng.
  2. Một chế độ xem khác bên ngoài ListView - nhưng tôi cần quan tâm đến việc di chuyển vị trí ListView xuống khi nó được kéo và tôi không chắc liệu chúng ta có thể phát hiện xem liệu kéo chạm vào ListView có thực sự cuộn các mục trên ListView hay không.

Có khuyến nghị nào không?

PS Tôi tự hỏi khi mã nguồn ứng dụng Twitter chính thức được phát hành. Nó đã được đề cập rằng nó sẽ được phát hành, nhưng 6 tháng đã trôi qua và chúng tôi đã không nghe về nó kể từ đó.


Là chức năng này có thể được thực hiện trong TableLayout được tạo động. Xin hãy giúp đỡ .....
Arun Badole

github.com/fruitranger/PulltorefreshListView là một triển khai khác của tôi. Hỗ trợ mượt mà và cảm ứng đa điểm.
Changwei Yao

6
Liên quan: Phần mềm Kéo để làm mới, một mẫu chống UI trên Android là một bài viết lập luận rằng giao diện người dùng này không phải là thứ nên được sử dụng trên Android và gây ra nhiều cuộc thảo luận về sự phù hợp của nó.
blahdibmus

29
Ai đó nên cho Google biết vì phiên bản Gmail mới nhất dành cho Android sử dụng "mẫu chống" này.
Nick

4
Kéo để làm mới là (và đã được một thời gian) một mẫu được áp dụng tiêu chuẩn trong iOS và Android và nó rất tự nhiên, vì vậy cuộc thảo luận chống mẫu này đã lỗi thời. Người dùng sẽ mong đợi để xem nó và hành xử như vậy.
Martin Marconcini

Câu trả lời:


311

Cuối cùng, Google đã phát hành phiên bản chính thức của thư viện pull-to-refresh!

Nó được gọi SwipeRefreshLayout, bên trong thư viện hỗ trợ và tài liệu ở đây :

  1. Thêm SwipeRefreshLayoutdưới dạng cha mẹ của khung nhìn sẽ được coi là một lực kéo để làm mới bố cục. (Tôi lấy ListViewví dụ, nó có thể Viewgiống như LinearLayout, ScrollViewv.v.)

    <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. Thêm người nghe vào lớp của bạn

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

Bạn cũng có thể gọi pullToRefresh.setRefreshing(true/false);theo yêu cầu của bạn.

CẬP NHẬT

Các thư viện hỗ trợ Android đã không còn được sử dụng và đã được thay thế bởi AndroidX. Liên kết đến thư viện mới có thể được tìm thấy ở đây .

Ngoài ra, bạn cần thêm phụ thuộc sau vào dự án của mình:

implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'

HOẶC LÀ

Bạn có thể truy cập Refactor >> Di chuyển sang AndroidX và Android Studio sẽ xử lý các phụ thuộc cho bạn.


3
Tôi có thể sử dụng ProgressBar thay vì Color Scheme trên SwipeRefreshLayout không?
pablobaldez

54
1 tháng 4, 14 - và đó không phải là một trò đùa
aeracode


80

Tôi đã cố gắng thực hiện một thành phần kéo để làm mới, nó chưa hoàn thành nhưng chứng tỏ khả năng triển khai có thể, https://github.com/johannilsson/android-pulltorefresh .

Logic chính được thực hiện trong PullToRefreshListViewđó mở rộng ListView. Trong nội bộ, nó kiểm soát việc cuộn chế độ xem tiêu đề bằng cách sử dụng smoothScrollBy(API Cấp 8). Tiện ích hiện được cập nhật với hỗ trợ cho 1.5 và sau đó, vui lòng đọc README cho hỗ trợ 1.5.

Trong bố trí của bạn, bạn chỉ cần thêm nó như thế này.

<com.markupartist.android.widget.PullToRefreshListView
    android:id="@+id/android:list"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
    />

3
Xin chào johan, tôi đã tải về mã mẫu của bạn. Nó được làm việc trong thiết bị Android 2.2 nhưng không hoạt động trong thiết bị 2.1. Tôi nghĩ bởi vì nó đã sử dụng phương thức smoothScrollBy chỉ có sẵn trong 2.2 trở lên, có đúng không? Và bạn có ý tưởng nào để thực hiện hiệu ứng này thành phiên bản 2.1 hoặc cũ hơn không? Cảm ơn

Có, đúng như tôi đã nêu trong câu trả lời smoothScrollBy đã được giới thiệu trong API Cấp 8 (2.2). Tôi chưa tìm ra cách thích hợp để triển khai nó cho các phiên bản khác, nhưng có thể đoán được là có thể chuyển việc triển khai smoothScrollBy nhưng tôi đoán rằng cuộc thảo luận nên được giữ tại trang web của dự án và không bị tràn stack?
Johan Berg Nilsson

Có phải mục đích là id là @ + id / android: list chứ không phải @android: id / list, nó có vẻ lạ không? Dự án đưa ra một lỗi lạm phát ở đây về phía tôi, tôi hiện đang kiểm tra điều đó ...
Mathias Conradt

12
Đây là thư viện tốt nhất để kéo để làm mới mà tôi đã tìm thấy .. github.com/chrisbanes/Android-PullToRefresh . Nó hoạt động với ListViews, GridViews và Webview. Cũng đã kéo lên để làm mới mô hình thực hiện.
rOrlig

1
Làm cách nào để thêm dự án vào thư mục thư viện trong khi làm việc trên Intellij Idea? Ai có thể giúp tôi?
Mustafa Güven

55

Tôi cũng đã triển khai một thư viện PullToRefresh mạnh mẽ, dễ sử dụng và tùy biến cao cho Android. Bạn có thể thay thế ListView của mình bằng PullToRefreshListView như được mô tả trong tài liệu trên trang dự án.

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


Tôi đã thử tất cả các triển khai được liệt kê ở đây và của bạn là tốt nhất, về mặt kéo đơn giản / thuần túy / trơn tru để làm mới việc thực hiện (không nhấn để làm mới sự kỳ lạ như của Johan). Cảm ơn!
Gady

1
Điều này có thể thay thế một ListView tiêu chuẩn để hoạt động với ListActivity, ListFragment hay không?
davidcesarino

Có, chỉ cần cung cấp cho PullToRefreshListView đúng id. Trong XML: android: id = "@ android: id / list"
Erik

1
Điều này là hoàn toàn tuyệt vời! google đưa tôi đến đây và xem qua các ví dụ, bạn có vẻ dễ thực hiện nhất. bravo và cảm ơn ngài!
Evan R.

Thành phần thiết kế rất hợp lý, đẹp và đơn giản. Điều này chắc chắn nên là câu trả lời được chấp nhận.
Adam

41

Cách dễ nhất tôi nghĩ là được cung cấp bởi thư viện hỗ trợ Android:

android.support.v4.widget.SwipeRefreshLayout;

một khi đã được nhập thì bạn có thể định nghĩa bố cục của mình như sau:

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

Tôi giả sử rằng bạn sử dụng chế độ xem tái chế thay vì listview. Tuy nhiên, listview vẫn hoạt động nên bạn chỉ cần thay thế recyclerview bằng listview và cập nhật các tham chiếu trong mã java (Fragment).

Trong đoạn hoạt động của bạn, trước tiên bạn triển khai giao diện , 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);

   }
}

Hy vọng điều này sẽ giúp công chúng


Nó hoạt động tốt. Mặc dù vậy, có một điều liên quan đến setRefreshing: "Đừng gọi điều này khi làm mới được kích hoạt bằng cử chỉ vuốt" như được mô tả trong developer.android.com/reference/android/support/v4/widget/
Lỗi

Làm tốt lắm! Cảm ơn.
Technik

22

Trong liên kết này, bạn có thể tìm thấy một ngã ba của PullToRefreshchế độ xem nổi tiếng có các triển khai thú vị mới như PullTorRefreshWebViewhoặc PullToRefreshGridViewhoặc khả năng thêm một PullToRefreshở cạnh dưới cùng của danh sách.

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

Và điều tuyệt nhất là nó hoạt động hoàn hảo trong Android 4.1 (bình thường PullToRefreshkhông hoạt động)


3
Một bình luận lớn ở đầu trang đọc cho biết: DỰ ÁN NÀY KHÔNG CÓ ĐƯỢC DỄ DÀNG HƠN. Dù sao, lib này là tốt nhất tôi đã thấy cho đến nay! Công việc tuyệt vời
Milton

3
Chỉ vì nó không còn được duy trì, không có nghĩa là nó không tốt. Vẫn sử dụng nó cho tất cả các nhu cầu của tôi để làm mới nhu cầu :)
Muz

18

Tôi có cách rất dễ dàng để làm điều này nhưng bây giờ chắc chắn đó là cách dễ dàng Có mã PullDownListView.java của tôi

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

Bạn chỉ cần triển khai ListViewTouchEventListener trên hoạt động của mình, nơi bạn muốn sử dụng ListView này và đặt trình nghe

Tôi đã thực hiện nó trong 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");
    }
}

Nó làm việc cho tôi :)


18

Để triển khai Android Pull-to-Refresh, hãy thử đoạn mã này,

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

Lớp hoạt động:

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

 }

1
Thanks.it thực sự đã giúp tôi
Arpan Sharma

9

Không ai đã đề cập đến loại "Kéo để làm mới" mới hiển thị trên đầu thanh hành động như trong ứng dụng Google Hiện hành hoặc Gmail.

Có một thư viện ActionBar-PullToRefresh hoạt động giống hệt nhau.


7

Lưu ý rằng có các vấn đề UX cần giải quyết khi triển khai trên Android và WP.

"Một chỉ số tuyệt vời cho lý do tại sao các nhà thiết kế / nhà phát triển không nên triển khai pull-to-refresh theo phong cách ứng dụng iOS làm là cách Google và các nhóm của họ không bao giờ sử dụng pull-to-refresh trên Android trong khi họ sử dụng nó trong iOS."

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


3
Tôi biết điều này đã hơn một năm tuổi nhưng ứng dụng Gmail không sử dụng pull-to-refresh. Tuy nhiên, nó không hoàn toàn giống nhau về giao diện người dùng, danh sách không cuộn xuống, thay vào đó là một chế độ xem mới hiển thị ở trên cùng của màn hình.
ashishduh

4

Nếu bạn không muốn chương trình của mình trông giống như một chương trình iPhone được trang bị cho Android, hãy nhắm đến một giao diện nguyên bản hơn và làm một cái gì đó tương tự như Gingerbread:

văn bản thay thế


2
@Rob: Tôi có nghĩa là có bóng màu cam ở đầu danh sách khi bạn quá tải, thay vì có danh sách bị trả lại như trên iPhone. Điều này có nghĩa là một nhận xét (không trả lời), nhưng ý kiến ​​không thể có hình ảnh.
Lie Ryan

Ahh, xin lỗi, ý tưởng tuyệt vời. Tôi chưa chơi với bánh gừng, nên chưa thấy hiệu quả. Vẫn đang chờ google để cuộn nó đến nexus.
Cướp

9
Tôi có Gingerbread và ánh sáng màu cam hoạt động tuyệt vời khi một danh sách tĩnh. Nhưng kéo xuống làm mới là một mecanism UI tuyệt vời để làm mới một danh sách động. Mặc dù nó phổ biến trong thế giới iOS, nhưng đó là một thủ thuật UI không gây cảm giác mạnh hơn trong hệ sinh thái Android. Tôi thực sự khuyên bạn nên kiểm tra nó trong ứng dụng Twitter chính thức. :)
Thierry-Dimitri Roy

Hành vi bản địa ở đây là để chỉ ra rằng bạn đã đạt đến cuối danh sách. Thực hiện điều này và thực hiện làm mới là hoàn toàn không có nguồn gốc vì bạn không làm những gì nền tảng làm. Điều này có nghĩa là bạn có nhiều khả năng gây ngạc nhiên cho người dùng. Tôi chắc chắn sẽ không mong muốn cũng không muốn làm mới chỉ vì tôi đã đến cuối danh sách. Kéo xuống để làm mới là trực quan và rõ ràng hơn rất nhiều. Và khi ứng dụng twitter gốc sử dụng nó, tôi nghĩ thật công bằng khi nói đây là một khái niệm UI, một lượng lớn người quen thuộc.
tủ quần áo

4

Tôi đã viết một thành phần kéo để làm mới ở đây: https://github.com/guillep/PullToRefresh Nó hoạt động sự kiện nếu danh sách không có mục và tôi đã thử nó trên> = 1.6 điện thoại Android.

Bất kỳ đề xuất hoặc cải tiến đều được đánh giá cao :)



1

Để nhận được Lollipop Pull-To Refresh mới nhất:

  1. Tải xuống thư viện hỗ trợ SDK và Extras / Android mới nhất của Lollipop
  2. Đặt mục tiêu xây dựng của dự án thành Android 5.0 (nếu không gói hỗ trợ có thể có lỗi với tài nguyên)
  3. Cập nhật libs / android-support-v4.jar của bạn lên phiên bản thứ 21
  4. Sử dụng android.support.v4.widget.SwipeRefreshLayoutcộngandroid.support.v4.widget.SwipeRefreshLayout.OnRefreshListener

Hướng dẫn chi tiết có thể được tìm thấy ở đây: http://antonioleiva.com/swiperefreshlayout/

Cộng với ListView tôi khuyên bạn nên đọc về canChildScrollUp()các bình luận;)


Thêm một chỉ để đề cập đến canChildScrollUp (). Rất quan trọng!
Petro

1

Pull-to-Refresh rất thú vị của Yalantis . Gif cho iOS, nhưng bạn có thể kiểm tra nó :)

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


0

Trước tiên chúng ta nên biết Pull để làm mới bố cục trong Android. chúng ta có thể gọi pull để làm mới trong Android là vuốt để làm mới. Khi bạn vuốt màn hình từ trên xuống dưới, nó sẽ thực hiện một số hành động dựa trên setOnRefreshListener.

Đây là hướng dẫn thể hiện về cách thực hiện kéo Android để làm mới. Tôi hi vọng cái này giúp được.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.