Some popular apps has an another approach: using loader view/loader holder. It's the default interface, visible when app launched and the data is blank. When data was loaded to device and available, loader holder view will disappear and real-data was displayed (usually by
TextView
and ImageView
). This approach make your app seem smoothly and more friendly!In this post, I will present a third-party called loaderviewlibrary to make this interface, output of loader view may be like this:
Importing library
build.gradle
to use this library:
dependencies {
compile 'com.elyeproj.libraries:loaderviewlibrary:1.0.3'
}
Now, we have 2 objects to build the loader view named LoaderTextView
and LoaderImageView
.Usages in XML
TextView
and ImageView
so we can use them normally in xml files.Define Loader View for
TextView
in layout XML:
<com.elyeproj.loaderviewlibrary.LoaderTextView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Loader View for ImageView
defined in layout XML:
<com.elyeproj.loaderviewlibrary.LoaderImageView
android:layout_width="100dp"
android:layout_height="100dp" />
Requirement: your project min-sdk must be 16 or higher.Sample project
ListView
first:
activity_main.xml
In each list view row (item), I have a <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="info.devexchanges.loaderview.MainActivity">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none" />
</RelativeLayout>
LoaderTextView
and LoaderImageView
to display data later:
item_listview.xml
Customizing a <?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="wrap_content"
android:orientation="horizontal"
android:paddingBottom="@dimen/activity_horizontal_margin">
<com.elyeproj.loaderviewlibrary.LoaderImageView
android:id="@+id/image_view"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerVertical="true" />
<com.elyeproj.loaderviewlibrary.LoaderTextView
android:id="@+id/text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_toRightOf="@id/image_view"
android:gravity="left"
android:maxHeight="120dp" />
</RelativeLayout>
ListView
adapter based on ArrayAdapter
:
ListViewAdapter.java
In the main activity, data will be loaded from URL when click on a button in option menu. Before it's clicked, list view data is blank and the loader holders will appear. Source code for this activity:
package info.devexchanges.loaderview;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
public class ListViewAdapter extends ArrayAdapter<String> {
private Activity activity;
private boolean isLoadImage;
private final static String IMAGE_URL = "http://i.imgur.com/cReBvDB.png";
public ListViewAdapter(Activity context, int resource, ArrayList<String> objects, boolean isLoadImage) {
super(context, resource, objects);
this.activity = context;
this.isLoadImage = isLoadImage;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
// If holder not exist then locate all view from UI file.
if (convertView == null) {
// inflate UI from XML file
convertView = inflater.inflate(R.layout.item_listview, parent, false);
// get all UI view
holder = new ViewHolder(convertView);
// set tag for holder
convertView.setTag(holder);
} else {
// if holder created, get tag from view
holder = (ViewHolder) convertView.getTag();
}
if (!getItem(position).equals("")) {
holder.countryName.setText(getItem(position));
}
if (isLoadImage) {
Picasso.with(activity).load(IMAGE_URL).into(holder.imageView);
}
return convertView;
}
private class ViewHolder{
private ImageView imageView;
private TextView countryName;
public ViewHolder (View view) {
imageView = (ImageView)view.findViewById(R.id.image_view);
countryName = (TextView)view.findViewById(R.id.text_view);
}
}
}
MainActivity.java
And the menu file:
package info.devexchanges.loaderview;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private ListView listView;
private ArrayList<String> strings;
private ArrayAdapter<String> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView)findViewById(R.id.list_view);
strings = new ArrayList<>();
for (int i = 0; i < 5; i++) {
strings.add("");
}
adapter = new ListViewAdapter(this, R.layout.item_listview, strings, false);
listView.setAdapter(adapter);
}
private void loadJSONDataFromURL() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
new GetJSONTask(MainActivity.this).execute();
}
}, 1000);
Log.i("Main", "load data");
}
//parsing json after getting from Internet
public void parseJsonResponse(String result) {
strings.clear();
try {
JSONObject json = new JSONObject(result);
JSONArray jArray = new JSONArray(json.getString("message"));
for (int i = 0; i < jArray.length(); i++) {
JSONObject jObject = jArray.getJSONObject(i);
strings.add(jObject.getString("name"));
}
adapter.notifyDataSetChanged();
Log.i("Main", "finish load data");
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.load) {
adapter = new ListViewAdapter(this, R.layout.item_listview, strings, true);
listView.setAdapter(adapter);
loadJSONDataFromURL();
}
return super.onOptionsItemSelected(item);
}
}
res/menu/main.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/load"
android:title="Load Data"
android:icon="@drawable/load"
app:showAsAction="always" />
</menu>
Important Note
:
- Request Internet permission in
AndroidManifest.xml
to get data from URLs:
<uses-permission android:name="android.permission.INTERNET"/>
- I use Picasso library to load image from an URL, please add it's dependency to app-level build.gradle
:
compile 'com.squareup.picasso:picasso:2.5.2'
Running application
Conclusions
Moreover, you can go to this library page on Github to read more details about it. Hope this is helpful with your work. Finally, you can get my full code by clicking the button below.