AndroidのScrollViewで、最下部までスクロールしたときに自動的に続きを読み込むなどの処理を実行したかったため、ScrollViewを継承して、最下部にスクロールしたイベントを検知できる独自クラスを作成しました。
ListViewでも同じようなことができますが、何らかの理由でListViewは使えないときのために。
MyScrollView.java
package sample.hara.myscrollview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ScrollView;
public class MyScrollView extends ScrollView {
public interface ScrollToBottomListener {
void onScrollToBottom(MyScrollView scrollView);
}
private ScrollToBottomListener scrollToBottomListener;
private int scrollBottomMargin = 0;
public MyScrollView(Context context) {
super(context);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyScrollView(Context context, AttributeSet attrs, int defs) {
super(context, attrs, defs);
}
public void setScrollToBottomListener(ScrollToBottomListener listener) {
this.scrollToBottomListener = listener;
}
public void setScrollBottomMargin(int value) {
this.scrollBottomMargin = value;
}
@Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
View content = getChildAt(0);
if (scrollToBottomListener == null) return;
if (content == null) return;
if (y + this.getHeight() >= content.getHeight() - scrollBottomMargin) {
scrollToBottomListener.onScrollToBottom(this);
}
}
}
レイアウトxmlファイルからでも使用できます。
setScrollBottomMargin(int)メソッドにより、最下部より指定したピクセル数だけ手前までスクロールしたときにイベントを走らせることもできます。
たとえば、ScrollView最下部にある何らかのviewが表示される領域までスクロールされたときに処理を行うならば、setScrollBottomMargin(view.getHeight())のように指定しておけばOKです。
利用例
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<sample.hara.myscrollview.MyScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout android:id="@+id/content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
<ProgressBar android:id="@+id/bottomView"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</sample.hara.myscrollview.MyScrollView>
MyScrollViewSampleActivity.java
package sample.hara.myscrollview;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
public class MyScrollViewSampleActivity extends Activity {
private static final int MAX = 500;
private MyScrollView scroll;
private View bottomView;
private LinearLayout layout;
private int count;
private ReadMoreTask readMoreTask;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
scroll = (MyScrollView) LayoutInflater.from(this).inflate(R.layout.main, null);
setContentView(scroll);
layout = (LinearLayout) scroll.findViewById(R.id.content);
bottomView = scroll.findViewById(R.id.bottomView);
for(count = 0; count < 50; count++) {
TextView tv = new TextView(this);
tv.setText(count + "");
layout.addView(tv);
}
scroll.setScrollToBottomListener(new MyScrollView.ScrollToBottomListener() {
@Override
public void onScrollToBottom(MyScrollView scrollView) {
if (count >= MAX) return;
if (readMoreTask != null) return;
readMoreTask = new ReadMoreTask();
readMoreTask.execute();
}
});
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
scroll.setScrollBottomMargin(bottomView.getHeight());
}
private class ReadMoreTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
return null;
}
@Override
protected void onPostExecute(Void result) {
for (int i = 0; i < 50; i++) {
TextView tv = new TextView(MyScrollViewSampleActivity.this);
tv.setText(count + i + "");
layout.addView(tv);
}
count += 50;
if (count >= MAX) bottomView.setVisibility(View.GONE);
readMoreTask = null;
}
};
}