ListView
is fairly common in Android application development. To day, in this tip, I will share a simple solution to detect scroll reached to top/bottom of ListView
and showing "header" and "footer" layout at this time. Another, when user scrolling, these layouts were disappeared.In order to do this, you must use
setOnScrollListener()
method of ListView
and in onScrollListener()
method, you provide some actions when scroll, reached to top/bottom.Source code for this method can be like this:
public OnScrollListener onScrollListener() {
return new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
if (firstVisibleItem == 0) {
// check if we reached the top or bottom of the list
View v = listView.getChildAt(0);
int offset = (v == null) ? 0 : v.getTop();
if (offset == 0) {
// reached the top: visible header and footer
Log.i(TAG, "top reached");
setViewStatus(footer, header, View.VISIBLE);
}
} else if (totalItemCount - visibleItemCount == firstVisibleItem) {
View v = listView.getChildAt(totalItemCount - 1);
int offset = (v == null) ? 0 : v.getTop();
if (offset == 0) {
// reached the bottom: visible header and footer
Log.i(TAG, "bottom reached!");
setViewStatus(footer, header, View.VISIBLE);
}
} else if (totalItemCount - visibleItemCount > firstVisibleItem){
// on scrolling
setViewStatus(footer, header, View.GONE);
Log.i(TAG, "on scroll");
}
}
};
}
In your activity, making some important methods (set data for ListView
, set some "demo" event listener for buttons in "header/footer" layout, show/hide these items,...):Full ReadingActivity.java code:
package com.blogspot.hongthaiit.mangareader;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class ReadingActivity extends Activity {
private ListView listView;
private ListViewAdapter adapter;
private View btnLike, btnShare, btnNext, btnPrev, btnComment;
private TextView chapterName;
private ViewGroup header, footer;
private final static String TAG = ReadingActivity.class.getSimpleName();
private final static String[] imageArray = { "http://i.imgur.com/bRzOCig.jpg",
"http://i.imgur.com/ykPVmnp.jpg", "http://i.imgur.com/RbKOKnG.jpg",
"http://i.imgur.com/REjrtGp.jpg", "http://i.imgur.com/PT9QjQ9.jpg",
"http://i.imgur.com/dg5NY1D.jpg", "http://i.imgur.com/Imlqk8j.jpg",
"http://i.imgur.com/U2IPvXy.jpg", "http://i.imgur.com/0MNYYuG.jpg",
"http://i.imgur.com/VZhAPel.jpg", "http://i.imgur.com/35jBerW.jpg",
"http://i.imgur.com/0jHZEfn.jpg", "http://i.imgur.com/81HvMfA.jpg",
"http://i.imgur.com/nobvCRi.jpg", "http://i.imgur.com/wdT3ZVw.jpg",
"http://i.imgur.com/DV9MDja.jpg", "http://i.imgur.com/PN2TQnS.jpg" };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reading);
listView = (ListView) findViewById(R.id.list_view);
locateListViewHeaderAndFooter();
setListViewAdapter();
//set on scrolling listener for ListView
listView.setOnScrollListener(onScrollListener());
}
// adding header and footer for listview
private void locateListViewHeaderAndFooter() {
// declaring elements
btnLike = findViewById(R.id.btn_like);
btnComment = findViewById(R.id.btn_comment);
btnNext = findViewById(R.id.btn_next);
btnPrev = findViewById(R.id.btn_prev);
btnShare = findViewById(R.id.btn_share);
chapterName = (TextView) findViewById(R.id.chapter_name);
header = (ViewGroup) findViewById(R.id.layout_header);
footer = (ViewGroup) findViewById(R.id.layout_footer);
chapterName.setText("One Piece chap 650");
// set "demo" events for buttons
btnLike.setOnClickListener(onButtonClick("You liked it"));
btnComment.setOnClickListener(onButtonClick("Please enter your comment..."));
btnNext.setOnClickListener(onButtonClick("Go to Next chap ter"));
btnPrev.setOnClickListener(onButtonClick("Go to Previous chap ter"));
btnShare.setOnClickListener(onButtonClick("Thanks for sharing..."));
}
private void setListViewAdapter() {
adapter = new ListViewAdapter(this, R.layout.item_listview, imageArray);
listView.setAdapter(adapter);
}
public OnScrollListener onScrollListener() {
return new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
if (firstVisibleItem == 0) {
// check if we reached the top or bottom of the list
View v = listView.getChildAt(0);
int offset = (v == null) ? 0 : v.getTop();
if (offset == 0) {
// reached the top: visible header and footer
Log.i(TAG, "top reached");
setViewStatus(footer, header, View.VISIBLE);
}
} else if (totalItemCount - visibleItemCount == firstVisibleItem) {
View v = listView.getChildAt(totalItemCount - 1);
int offset = (v == null) ? 0 : v.getTop();
if (offset == 0) {
// reached the bottom: visible header and footer
Log.i(TAG, "bottom reached!");
setViewStatus(footer, header, View.VISIBLE);
}
} else if (totalItemCount - visibleItemCount > firstVisibleItem){
// on scrolling
setViewStatus(footer, header, View.GONE);
Log.i(TAG, "on scroll");
}
}
};
}
// handle buttons events
private OnClickListener onButtonClick(final String buttonEventName) {
return new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(ReadingActivity.this, buttonEventName, Toast.LENGTH_SHORT).show();
}
};
}
private void setViewStatus(ViewGroup vg1, ViewGroup vg2, int status) {
vg1.setVisibility(status);
vg2.setVisibility(status);
}
}
ListView
:
ListViewAdapter.java
Over here, programmatically codes completed. Declaring necessary layouts in xml files:package com.blogspot.hongthaiit.mangareader;
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 com.squareup.picasso.Picasso;
public class ListViewAdapter extends ArrayAdapter {
private Activity activity;
public ListViewAdapter(Activity activity, int resource, String[] objects) {
super(activity, resource, objects);
this.activity = activity;
}
@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();
}
//load image from url by Picasso library
Picasso.with(activity).load(getItem(position)).into(holder.page);
return convertView;
}
private class ViewHolder {
private ImageView page;
public ViewHolder(View v) {
page = (ImageView) v.findViewById(R.id.image);
}
}
}
- layout_header.xml: the view above
ListView
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout_footer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#91000000"
android:orientation="horizontal"
android:padding="5dp" >
<ImageView
android:id="@+id/btn_prev"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.2"
android:contentDescription="@string/app_name"
android:src="@drawable/previous" />
<TextView
android:id="@+id/chapter_name"
android:layout_width="0dp"
android:textStyle="bold"
android:layout_gravity="center"
android:gravity="center"
android:layout_height="wrap_content"
android:layout_weight="0.6"
android:textColor="@android:color/white" />
<ImageView
android:id="@+id/btn_next"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.2"
android:contentDescription="@string/app_name"
android:src="@drawable/next" />
</LinearLayout>
- layout_footer.xml: the view below
ListView
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout_header"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#91000000"
android:orientation="horizontal"
android:padding="5dp" >
<ImageView
android:id="@+id/btn_like"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:contentDescription="@string/app_name"
android:src="@drawable/like" />
<ImageView
android:id="@+id/btn_comment"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:contentDescription="@string/app_name"
android:src="@drawable/comment" />
<ImageView
android:id="@+id/btn_share"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.33"
android:contentDescription="@string/app_name"
android:src="@drawable/share" />
</LinearLayout>
- activity_reading.xml: activity layout, we'll include 2 above items here:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
<include
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
layout="@layout/layout_header" />
<include
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
layout="@layout/layout_footer" />
</RelativeLayout>
- item_listview.xml: each
ListView
item layout - only include anImageView
:
item_listview.xml
Running program, our result will be liked this:<LinearLayout 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:orientation="horizontal"
android:padding="5dp" >
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/action_settings"
android:scaleType="fitXY" />
</LinearLayout>
NOTE:
In this post, I use Picasso library to load images from urls:
- See my PREVIOUS POST to learn how to use it.