Pull To Refresh Layout by external library in Android

Pull To Refresh Layout by external library in Android


    Pull To Refresh is an exciting topic in Android programming. Pull to refresh is the hottest android UI pattern used by developers in their applications to improve the usability. You can see this pull to refresh feature in many android applications  like Gmail, Facebook, Twitter etc…
    As you can search on Internet, there are many libraries help us to dealing with this problem, I also had a post about using a library written by Chris Banes in Eclipse project format, you can take a glance.
    Moreover, with Material Design technology, Google has released SwipeRefreshLayout, that working well, although it don't have many customs. You can see how to use it at this POST.
    In this  tutorial I’ll show you how to use pull to refresh feature in your android application by using an another powerful external library called Ultra-Pull-To-Refresh, it support all containers and widgets.

Importing library to Android project

    After starting Android Studio project, open your app/build.gradle and add this lib dependency:
dependencies {
compile 'in.srain.cube:ultra-ptr:1.0.11'
}

XML declaring

    Firstly, we must put PtrClassicFrameLayout or PtrClassicFrameLayout to the activity layout file (xml) to use pull to refresh feature. These classes extend ViewGroup, so you can put any view containers (FrameLayout, RelativeLayout,...) or widgets (ListView, GridView,...) inside them.
    Important NOTE: Both of containers can contain only one directly child view.
    For example, creating an activity layout like this:
activity_main.xml
<in.srain.cube.views.ptr.PtrClassicFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:cube_ptr="http://schemas.android.com/apk/res-auto"
    android:id="@+id/pt_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    cube_ptr:ptr_duration_to_close="200"
    cube_ptr:ptr_duration_to_close_header="1000"
    cube_ptr:ptr_keep_header_when_refresh="true"
    cube_ptr:ptr_pull_to_fresh="false"
    cube_ptr:ptr_ratio_of_header_height_to_refresh="1.2"
    cube_ptr:ptr_resistance="1.7">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="@dimen/activity_horizontal_margin"
        android:paddingTop="100dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:orientation="horizontal">

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.35"
                android:text="@string/country"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/city"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.65"
                android:textColor="@android:color/holo_green_light" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:orientation="horizontal">

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.35"
                android:text="@string/location"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/location"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.65"
                android:textColor="@android:color/holo_blue_dark" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:orientation="horizontal">

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.35"
                android:text="@string/temperature"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/temperature"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.65"
                android:textColor="@android:color/holo_orange_dark" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:orientation="horizontal">

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.35"
                android:text="@string/humidity"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/humidity"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.65"
                android:textColor="@android:color/holo_purple" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:orientation="horizontal">

            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.35"
                android:text="@string/pressure"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/pressure"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.65"
                android:textColor="@android:color/holo_red_dark" />
        </LinearLayout>

    </LinearLayout>

</in.srain.cube.views.ptr.PtrClassicFrameLayout>

Coding project

    In this example, at programmatically code, I use an AsyncTask to get data from Internet after user pull the layout, the view will be refreshed when AsyncTask done:
GetWeatherTask.java
package info.devexchanges.ultrapulltorefresh;

import android.app.ProgressDialog;
import android.os.AsyncTask;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class GetWeatherTask extends AsyncTask<Void, Void, String> {

    private HttpURLConnection urlConnection;
    private final String JSON_URL = "http://api.openweathermap.org/data/2.5/weather?q=hanoi,vn&appid=44db6a862fba0b067b1930da0d769e98";
    private MainActivity activity;
    private ProgressDialog progressDialog;

    public GetWeatherTask(MainActivity activity) {
        this.activity = activity;
        progressDialog = ProgressDialog.show(activity, "Connecting...", "Downloading JSON...", true);
    }

    @Override
    protected String doInBackground(Void... params) {

        StringBuilder result = new StringBuilder();

        try {
            URL url = new URL(JSON_URL);
            urlConnection = (HttpURLConnection) url.openConnection();
            InputStream in = new BufferedInputStream(urlConnection.getInputStream());
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));

            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            urlConnection.disconnect();
        }

        return result.toString();
    }

    @Override
    protected void onPostExecute(String result) {
        progressDialog.dismiss(); //dismiss dialog
        activity.parsingJSON(result); //call back data to UI thread
    }
}

    Your Activity must implements PtrHandler interface and there are 2 methods need to override:
  • onRefreshBegin(): when user release pulling action, this will be invoked.
  • checkCanDoRefresh(): set anable/disable for pull to refresh feature.
    Full code of this Activity:
MainActivity.java
package info.devexchanges.ultrapulltorefresh;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import org.json.JSONException;
import org.json.JSONObject;

import java.math.BigDecimal;
import java.math.RoundingMode;

import in.srain.cube.views.ptr.PtrClassicFrameLayout;
import in.srain.cube.views.ptr.PtrFrameLayout;
import in.srain.cube.views.ptr.PtrHandler;

public class MainActivity extends AppCompatActivity implements PtrHandler {

    private PtrClassicFrameLayout pullToRefreshLayout;
    private TextView location;
    private TextView city;
    private TextView pressure;
    private TextView humidity;
    private TextView temperature;

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

        temperature = (TextView) findViewById(R.id.temperature);
        city = (TextView) findViewById(R.id.city);
        location = (TextView) findViewById(R.id.location);
        humidity = (TextView) findViewById(R.id.humidity);
        pressure = (TextView) findViewById(R.id.pressure);
        pullToRefreshLayout = (PtrClassicFrameLayout) findViewById(R.id.pt_frame);

        //set handler for pull to refresh layout
        pullToRefreshLayout.setPtrHandler(this);
        //set last update time in header
        pullToRefreshLayout.setLastUpdateTimeRelateObject(this);
    }

    @SuppressLint("SetTextI18n")
    public void parsingJSON(String data) {
        // parsing json and set the custom dialog components - text, image and button
        try {
            JSONObject jsonObject = new JSONObject(data);

            //get location
            JSONObject locationObject = jsonObject.getJSONObject("coord");
            location.setText("[ " + locationObject.getString("lon") + ", " + locationObject.getString("lat") + " ]");

            //get temperature, humidity and pressure
            JSONObject tempObject = jsonObject.getJSONObject("main");
            temperature.setText(kelvinToCelcius(tempObject.getString("temp")) + " " + (char) 0x00B0 + "C");
            humidity.setText(tempObject.getString("humidity") + "%");
            pressure.setText(hPaToatm(tempObject.getString("pressure")) + " atm");

            //get city name
            city.setText(jsonObject.getString("name"));
        } catch (JSONException e) {
            e.printStackTrace();
        }

        pullToRefreshLayout.refreshComplete(); //stop Refreshing
    }

    @Override
    public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
        return true;
    }

    @Override
    public void onRefreshBegin(PtrFrameLayout frame) {
        new GetWeatherTask(this).execute();
    }

    public double kelvinToCelcius(String kelvin) {
        BigDecimal bd = new BigDecimal(Double.parseDouble(kelvin) - 273);
        bd = bd.setScale(2, RoundingMode.HALF_UP);

        return bd.doubleValue();
    }

    public double hPaToatm(String hPa) {
        BigDecimal bd = new BigDecimal((Double.parseDouble(hPa) / 1013.25));
        bd = bd.setScale(2, RoundingMode.HALF_UP);

        return bd.doubleValue();
    }
}
    Strings resource for this project:
strings.xml
<resources>
    <string name="app_name">"Ultra Pull To Refresh"</string>
    <string name="notice">Pull down to refresh</string>
    <string name="location">Location</string>
    <string name="country">City:</string>
    <string name="temperature">Temperature:</string>
    <string name="humidity">Humidity:</string>
    <string name="pressure">Pressure:</string>
    <string name="weather">Weather</string>
</resources>

    Running application, you'll have this result:

Customizing Pull To Refresh Header

    This library provide a simplest way to custom the pull to refresh layout header text is set new value for it's default strings resource. Rewrite your strings.xml like this:
strings.xml
<resources>
    <string name="app_name">"Ultra Pull To Refresh"</string>
    <string name="notice">Pull down to refresh</string>
    <string name="location">Location</string>
    <string name="country">City:</string>
    <string name="temperature">Temperature:</string>
    <string name="humidity">Humidity:</string>
    <string name="pressure">Pressure:</string>
    <string name="weather">Weather</string>

    <!--Customizing pull to refresh layout header texts -->
    <string name="cube_ptr_pull_down_to_refresh">Kéo xuống để làm mới</string>
    <string name="cube_ptr_release_to_refresh">Thả để làm mới</string>
    <string name="cube_ptr_refreshing">Đang cập nhật...</string>
    <string name="cube_ptr_refresh_complete">Đã cập nhật!</string>
    <string name="cube_ptr_pull_down">Kéo xuống</string>
    <string name="cube_ptr_last_update">Cập nhật lần cuối:&#160;</string>
    <string name="cube_ptr_seconds_ago">&#160;giây trước</string>
    <string name="cube_ptr_minutes_ago">&#160;phút trước</string>
    <string name="cube_ptr_hours_ago">&#160;giờ trước</string>
</resources>

    And this is new output:
    Of course, if you want to make more complicated header, use setHeader(View view) of PtrFrameLayout or PtrClassicFrameLayout with view is inflating from a XML file. For example:
LayoutInflater inflater = (LayoutInflater)getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View header = inflater.inflate(R.layout.layout_header, null);
pullToRefreshLayout.setHeaderView(header);

Conclusions & References

   Ultra-Pull-To-Refresh may be the best library in making a pull to refresh layout. From here, you can visit it's page on @Github to read it's documents to find out more exciting features of this powerful library. Further, please read my previous post about another lib written by Chris Banes or visit this post to learn about using the official widget provided by Google.


Android Pull To Refresh by using external Libraries

Android Pull To Refresh by using external Libraries

    In previous post, I have showed how to use SwipeRefreshLayout - an official widget of refreshing View (ListView, ScrollView,...). But there are a lot of external libraries which provide us more animations, UI design options and they're more poppular than the default ones.
In this tut, I'll show you how to make a refreshable layout by using ActionBar-PullToRefresh library (developed by Chris Banes).

1. Download 2 necessary libraries

These libraries written in Android Studio project format so we must config them to use in Eclipse. For convenient, I have fixed them already. You can download at:
- SmoothProgressBar: Link
- ActionBar-PullToRefreshLink 

2. Import these project to eclipse and make reference

After import them, with SmoothProgressBar:
- Right Click  project  name and goto “Properties”
- Choose Android tab, under Library area check "Is Library" check box.
- Remember choosing Project Build Target 5.0 or higher.
With ActionBar-PullToRefresh: similar as bove, after that, make reference with smoothprogressbar project by click Add button:


3. Start a new Android Project to using them

Min-sdk I used is 14.
Before coding, remember to make this project reference to 2 libraries (like above picture). In this project, I will parse xml from an url and getting data to views after an AsyncTask done.
Declaring an activity layout (activity_pull_to_refresh.xml):

Make a customize AsyncTask to get data from Internet (Weather data):
In our activity, we must:
- config PullToRefreshLayout properties (in onCreate() method of Activity, after locate views).
- Implement pull to refresh library OnRefreshListener and override onRefreshStarted() method.
- set setRefreshComplete() after receive response data successful.

Full PullToRefreshActivity.java code:
Make some strings in resource (strings.xml):
Open AndroidManifest.xml and add Internet permission:
Some app screens:
pic name pic name pic name
NOTE:
- ActionBar-PullToRefresh official in Github: https://github.com/chrisbanes/ActionBar-PullToRefresh
- SmoothProgressBar official in Github: https://github.com/castorflex/SmoothProgressBar
- You can see how to fix 2 libraries to use in Eclipse at this tutorial.
- Libraries Author Homepage: https://chris.banes.me/
- My SwipeRefreshLayout tutorial post: HERE!

(Sorry for having ads)

Android - SwipeRefreshLayout example (an Android Material Design UI Pattern)

Android - SwipeRefreshLayout example (an Android Material Design UI Pattern)

    One of the great ideas formalized in the new Material Design user interface guidelines is the Swipe to Refresh UI pattern. In fact, you’ve probably already seen and used it. It’s found its way into many popular Android apps like Facebook, Google Newsstand, Trello, Gmail and many others.

    SwipeRefreshLayout is very useful when we work with data from Internet or Server. With a simple action, we'll update data.
    In this post, I present a simple project that:
- Get JSON data from an URL.
- Parse JSON and populating data to a ListView.
- Swipe to refresh/ update data.

1. Lauch Eclipse and start a new Android Project (min-sdk is 14).
2. Create a model object for our project (Student.java):
3. Create layout for launching activity (activity_swipe.xml):
4. Give a Custom AsyncTask to get data from Internet through an URL like this:
5. In SwipeActivity, we must:
- set OnRefreshListener for SwipeRefreshLayout.
- execute AsyncTask and get data after it's done.
- set/notify adapter for ListView.
Full code:
6. Okey, these are some necessary class/ layout in project:
- A custom Adapter for ListView:
- Layout for each ListView row(item_listview.xml):
- Some own colors use in projects (res/values/colors.xml):
7. Some result screens:

pic name pic name pic name
(Sorry for having ads)