12/08/2018, 14:09

How to make Pull To Reresh into your App

Để có thể luôn hiển thị những dữ liệu mới nhất, chúng ta thường thực hiện cập nhật dữ liệu một cách tự động trong 1 thời gian ngắn hoặc 1 thời gia khá dài, trong nhiều trường hợp đó không phải hoàn toàn là một cách hay từ phía user, nó có thể gây tiêu tốn lưu lượng mà khiến user thấy đó là không ...

Để có thể luôn hiển thị những dữ liệu mới nhất, chúng ta thường thực hiện cập nhật dữ liệu một cách tự động trong 1 thời gian ngắn hoặc 1 thời gia khá dài, trong nhiều trường hợp đó không phải hoàn toàn là một cách hay từ phía user, nó có thể gây tiêu tốn lưu lượng mà khiến user thấy đó là không cần thiết hoặc cũng có thể khiến user thấy lâu có hàng mới thế. Vì vậy sao ta ko để user có thể tự mình cập nhật dữ liệu mới khi thấy cần thiết. Và thật hay ho là nền tảng Android cung cấp cho chúng ta một design pattern swipe-to-refresh để thực hiện việc đó.

Ví dụ đối với các ứng dụng thời tiết, khi user muốn biết bây giờ lạnh bao nhiêu độ thì chỉ đơn giản là kéo ngón tay từ top màn hình xuống để refresh data, thật tiện lợi phải không.

Screenshot_20161101-152640.png

Chú ý: Lớp này yêu cần phiên bản mới nhất của Android v4 Support Library APIs.

Adding Swipe-to-Refresh To Your App

Để có thể tạo được tính năng Swipe-to-Refresh ta cần sử dụng một widget tiện ích là SwipeRefreshLayout, nó sẽ giúp chúng ta xác định được việc vuốt dọc, hiển thị một distinctive progress bar để thể hiện công việc refresh, và tất nhiên sẽ có phương thức triggers callback để làm nhiều việc. Và để sử dụng ta sẽ để SwipeRefreshLayout là cha của những layout mà bạn muốn add tính năng Swipe-to-Refresh ví như ListView, GridView và thực hiện refresh khi người dùng vuốt và vuốt.

Add the SwipeRefreshLayout Widget

Add SwipeRefreshLayout như là cha của một ListView đơn hoặc GridView. Chú ý là SwipeRefreshLayout chỉ hỗ trợ cho một ListView đơn hoặc GridView.

Ví dụ add SwipeRefreshLayout cho một ListView

<android.support.v4.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swiperefresh"
    android:layout_awidth="match_parent"
    android:layout_height="match_parent">

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

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

Bạn cũng có thể sử dụng SwipeRefreshLayout với một ListFragment. Nếu layout bao gồm một ListVIew với ID "@android:id/list" thì tính năng swipe-to-refresh tự động được hỗ trợ. Tuy nhiên khai báo ListView một cách rõ ràng là cách này thay thế cấu trúc ListFragment view mặc định. Nếu bạn muốn sử dụng các cấu trúc mặc định, bạn phải override các hành vi của SwipeRefreshLayout và ListFragment.

Add a Refresh Action to the Action Bar

Bạn nên thêm một hành động refresh vào trong action bar của app để đảm bảo răng người dùng vẫn có thể thực hiện được việc refresh thủ công khi mà bạn ý không có khả năng swipe vuốt xuống. Ví dụ khi người dùng sử dụng các thiết bị ngoài như keyboards và D-pads thì việc thêm một option vào actionbar cũng khá cần thiết. (Cái này tùy)

Bạn nên thêm hành động refresh như là một menu item chứ không phải là một button, bằng các thiết lập thuộc tính android:showAsAction=never . Nếu bạn hiển thị hành động này như là một button, người dùng có thể bị hiểu nhầm rằng hành động swipe to refresh là một, button refresh là một - 2 cái khác nhau. Bằng cách làm cho hành động refresh ít bị chú ý trong action bar, bạn cũng có thể khuyến khích người dùng thực hiện cập nhật bằng tay với cử chỉ vuốt - swipe, đồng thời vẫn duy trì hành động refresh trong acction bar nơi mà những người sử dụng D-pad sẽ thấy.

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/menu_refresh"
        android:showAsAction="never"
        android:title="@string/menu_refresh"/>
</menu>

Responding to a Refresh Request

Phía trên ta đã nói cách khai báo SwipeRefreshLayout trong layout, và giờ làm thế nào để handle được acction refresh từ phía người dùng. Chúng ta hãy theo dõi tiếp bên dưới.

Respond to the Refresh Gesture

Khi người dùng thực hiện một hành động swipe, thì hệ thống sẽ hiển thị một progress bar và gọi phương thức callback của app. Callback này sẽ có tách nhiệm thực hiện cập nhật dữ liệu của ứng dụng.

Để response lại các hành động refresh của user, ta thực hiện implement một listener onRefresh() cho SwipeRefreshLayout: SwipeRefreshLayout.OnRefreshListener. Phương thức onRefresh() sẽ được gọi đến khi user thực hiện hành động swipe to refresh.

Bạn nên thực hiện công việc cập nhật dữ liệu cho ứng dụng trong một phương thức riêng tự định nghĩa, và gọi nó trong phương thức onRefresh() khi có hành động từ phía người dùng. Bằng cách như vậy bạn vừa có thể thự hiện cập nhật khi có hành động, vừa có thể thực hiện cập nhật theo ý muốn tại một tác vụ khác nào đó như là trong acction bar vừa nêu ở trên.

Khi hoàn thành xong công việc cập nhật đừng quên gọi phương thức setRefreshing(false), false hay success cũng gọi hết. Nó sẽ thực hiện ẩn progress bar và cập nhật nội dung.

mySwipeRefreshLayout.setOnRefreshListener(
    new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            Log.i(LOG_TAG, "onRefresh called from SwipeRefreshLayout");

            // This method performs the actual data-refresh operation.
            // The method calls setRefreshing(false) when it's finished.
            myUpdateOperation();
        }
    }
);

private void myUpdateOperation() {
	// call api to update data
	// don't forget call setRefreshing(false) when finish
	apiService.getData()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Data>() {
                    @Override
                    public void onCompleted() {
                        mySwipeRefreshLayout.setRefreshing(false);
                    }

                    @Override
                    public void onError(Throwable e) {
                        mySwipeRefreshLayout.setRefreshing(false);
                    }

                    @Override
                    public void onNext(Data data) {

                    }
                });
}

Respond to the Refresh Action

Khi người dùng thực hiện refresh từ acction bar, chúng ta thực hiện các hành động hiển thị progress bar và cập nhật dữ liệu.

Ta sẽ thực hiện gọi phương thức setRefreshing(true) khi có hành động refresh, và gọi phương thức cập nhật riêng (đây là 1 lý do nên viết phương thức cập nhật riêng rẽ, lúc nào cần thì gọi đến). Và cũng như trên, khi hoàn thành cập nhật thì ta thực hiện gọi setRefreshing(false) để ẩn progress bar.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        // Check if user triggered a refresh:
        case R.id.menu_refresh:
            Log.i(LOG_TAG, "Refresh menu item selected");

            // Signal SwipeRefreshLayout to start the progress indicator
            mySwipeRefreshLayout.setRefreshing(true);

            // Start the refresh background task.
            // This method calls setRefreshing(false) when it's finished.
            myUpdateOperation();

            return true;
    }

    // User didn't trigger a refresh, let the superclass handle this action
    return super.onOptionsItemSelected(item);

}

Sample

gif.gif

0