How to add pull to refresh in AppBarLayout
Asked Answered
C

4

12

I find most of the material is about discussing adding "pull to refresh" in the area below AppBarLayout, such as SwipeRefreshLayout, I wonder how to do this in the AppBarLayout, which means:

enter image description here

When pull down, the pull-to-refresh indicator appeaars in the AppBarLayout.

how to implement this? Thanks

=================UPDATE===================

I finally worked it out on my own way. Here is the video link recording the simple UI.

The key point is I rewrite the appbarlayout-spring-behavior from github. It's really helpeful. Simply put, I rewrited the AppBarLayoutSpringBehavior, adding a Pull-To-Refresh-Callback when draging, and add some logic to displaying the pull-to-refresh animation prevent simplely animating back to original state. After sometime, then I tell the behavior to animate back.

Though the rewriten code seems ugly, but it seems feasible. I will refactor my code to make it clean and modular

Coelom answered 27/7, 2017 at 14:42 Comment(0)
T
2

I have wrote one nestrefresh repo which you can add pull refresh for the header same to AppBarLayout. You can add pull to refresh for child in ViewPager or pull to load more. You can use ChildCoordinatorLayout in my repo to wrap AppBarLayout if you want to use AppBarLayout only. But when scroll AppBarLayout can not refresh because of AppBarLayout has not send scroll event to parent. So you can try RefreshBarLayout in the repo.

Trinary answered 23/7, 2019 at 7:2 Comment(0)
P
1

EDIT Added the ProgressBar inside the AppBarLayout.

You need to wrap the ReyclerView with a SwipeRefreshLayout like you said and also add a ProgressBar into a custom ToolBar:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.myapplication.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center">

                <TextView
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_gravity="start"
                    android:layout_weight="1"
                    android:gravity="start|center"
                    android:text="@string/app_name"
                    android:textColor="@android:color/white" />

                <ProgressBar
                    android:id="@+id/a_main_progress"
                    android:layout_width="24dp"
                    android:layout_height="24dp"
                    android:layout_marginEnd="10dp"
                    android:layout_marginRight="10dp"
                    android:visibility="invisible" />

            </LinearLayout>
        </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/a_main_swipe"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/a_main_recycler"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

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

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

</android.support.design.widget.CoordinatorLayout>

You will also need to set the listener in your MainActivity:

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private SwipeRefreshLayout swipeRefreshLayout;
    private ProgressBar progressBar;

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

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.a_main_swipe);
        progressBar = (ProgressBar) findViewById(R.id.a_main_progress);

        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                progressBar.setVisibility(View.VISIBLE);
                Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        // Simulates a long running task (updating data)
                        swipeRefreshLayout.setRefreshing(false);
                        progressBar.setVisibility(View.INVISIBLE);
                    }
                }, 2000);
            }
        });

        MainAdapter mainAdapter = new MainAdapter(Arrays.asList("Hello", "World", "Bye"));
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.a_main_recycler);
        recyclerView.setAdapter(mainAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
    }
}

This is a simple adapter code if you needed it too:

MainAdapter.java

public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> {

    private List<String> strings;

    public MainAdapter(List<String> strings) {
        this.strings = strings;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        View view = layoutInflater.inflate(android.R.layout.simple_list_item_1, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.bind(strings.get(position));
    }

    @Override
    public int getItemCount() {
        return strings != null ? strings.size() : 0;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        private final TextView textView;

        public ViewHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(android.R.id.text1);
        }

        public void bind(String s) {
            textView.setText(s);
        }
    }
}

This is the updated Result:

Result ProgressBar

Pastose answered 27/7, 2017 at 15:25 Comment(5)
I need the pull-to-refresh indicator inside the appbarlayout. It should move together when Appbarlayout moves.Coelom
You mean as an icon inside the AppBarLayout?Pastose
yes. can i make this? I found it is more complicated than i thoughtCoelom
Maybe I need write a customized behavior to do this. No idea if there is any sampleCoelom
Alright, I edited the answer, you would only need to spend some time styling it.Pastose
C
1

I finally worked it out on my own way. Here is the video link recording the simple UI.

The key point is I rewrite the appbarlayout-spring-behavior from github. It's really helpeful. Simply put, I rewrited the AppBarLayoutSpringBehavior, adding a Pull-To-Refresh-Callback when draging, and add some logic to displaying the pull-to-refresh animation prevent simplely animating back to original state. After sometime, then I tell the behavior to animate back.

Though the rewriten code seems ugly, but it seems feasible. I will refactor my code to make it clean and modular

Coelom answered 28/7, 2017 at 14:57 Comment(1)
Can you please share the updated code of AppBarLayoutSpringBehaviour?Checkoff
B
0

You can try a view hierarchy like this

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingTop="?attr/actionBarSize">

        <android.support.v7.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@+id/appBar"/>
    </android.support.v4.widget.SwipeRefreshLayout>

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v7.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"/>
    </android.support.design.widget.AppBarLayout>
</RelativeLayout>

In your Java class, you can use your SwipeRefreshLayout like this

swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
swipeRefreshLayout.setProgressViewOffset(false, 0, (int) (swipeRefreshLayout.getPaddingTop() * 1.5));
swipeRefreshLayout.setOnRefreshListener(() -> {
    swipeRefreshLayout.setRefreshing(true);
    // long process here
    new Handler().postDelayed(() -> runOnUiThread(() -> swipeRefreshLayout.setRefreshing(false)), 2000);
});
Butter answered 27/7, 2017 at 14:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.