HorizontalScrollView から無限ページャーを作成しようとしています。
必要に応じて子ビューを継続的に再配置することで無限にスクロールしますが、ビューの移動 (左または右への追加) を開始する必要があると、スムーズにスクロールしなくなります。子の位置を変更した後でも、スムーズに次のページにスクロールする方法を見つけようとしています。
これまでのクラスは次のとおりです。
import java.util.HashMap;
import java.util.Map;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
public class PagerInfinite extends HorizontalScrollView {
private LinearLayout contents;
private Map<Integer, Integer> childWidths = new HashMap<Integer, Integer>();
private int childSpacing = 0;
private int activePageIndex = 1;
private float oldX = 0f;
private float oldY = 0f;
private boolean firstScroll = true;
public PagerInfinite(Context context, AttributeSet attrs) {
super(context, attrs);
this.contents = new LinearLayout(context);
this.contents.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT));
this.addView(this.contents);
setVerticalScrollBarEnabled(false);
setHorizontalScrollBarEnabled(false);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
for (int i = 0; i < this.contents.getChildCount(); i++) {
View child = this.contents.getChildAt(i);
int width = child.getWidth();
if(width != 0) {
this.childWidths.put(i, width);
}
}
if(this.childWidths.size() > 0 && this.firstScroll) {
this.smoothScrollTo(this.getActivePageOffset(), 0);
this.firstScroll = false;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected float getLeftFadingEdgeStrength() {
return 0.0f;
}
@Override
protected float getRightFadingEdgeStrength() {
return 0.0f;
}
public void addPage(View child) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.setMargins(0, 0, this.childSpacing, 0);
child.setLayoutParams(params);
if(this.contents.getChildCount() <= 1) {
this.contents.addView(child);
} else if(this.contents.getChildCount() <= 2) {
this.contents.addView(child, 0);
} else {
View last = this.contents.getChildAt(0);
this.contents.removeView(last);
this.contents.addView(last);
this.contents.addView(child, 0);
}
this.contents.requestLayout();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = super.onTouchEvent(event);
switch(event.getAction()) {
case(MotionEvent.ACTION_DOWN):
this.oldX = event.getX();
this.oldY = event.getY();
break;
case(MotionEvent.ACTION_UP):
float newX = event.getX();
float newY = event.getY();
float deltaX = newX - this.oldX;
float deltaY = newY - this.oldY;
// Use deltaX and deltaY to determine the direction
if(Math.abs(deltaX) > Math.abs(deltaY)) {
if(deltaX > 0) {
// right
if(this.activePageIndex <= 1) {
this.buildLeft();
} else {
this.activePageIndex -= 1;
}
} else {
// left
if(this.activePageIndex >= this.contents.getChildCount() - 2) {
this.buildRight();
} else {
this.activePageIndex += 1;
}
}
}
this.smoothScrollTo(this.getActivePageOffset(), 0);
break;
}
return result;
}
private void buildLeft() {
View view = this.contents.getChildAt(this.contents.getChildCount() - 1);
this.contents.removeView(view);
this.contents.addView(view, 0);
}
private void buildRight() {
View view = this.contents.getChildAt(0);
this.contents.removeView(view);
this.contents.addView(view);
}
private int getActivePageOffset() {
Log.d(LCHApplication.TAG, "ActiveIndex = " + this.activePageIndex);
if(this.activePageIndex == 0) {
return 0;
}
if(this.activePageIndex == this.contents.getChildCount() - 1) {
return this.contents.getWidth();
}
int offset = 0;
for(Map.Entry<Integer, Integer> entry : this.childWidths.entrySet()) {
if(entry.getKey() < this.activePageIndex) {
offset += entry.getValue() + this.childSpacing;
} else {
break;
}
}
offset += (this.childWidths.get(this.activePageIndex) / 2);
offset -= (LCHApplication.instance.width / 2);
return offset;
}
public boolean hasPage(View v) {
return this.contents.indexOfChild(v) != -1;
}
public void removePage(View v) {
int index = this.contents.indexOfChild(v);
this.contents.removeView(v);
this.childWidths.remove(index);
}
public int getCurrentPageIndex() {
return this.activePageIndex;
}
public int getPageCount() {
return this.contents.getChildCount();
}
public void removeAllPages() {
this.contents.removeAllViews();
this.childWidths = new HashMap<Integer, Integer>();
}
public void cycle() {
if(this.activePageIndex < this.contents.getChildCount() - 1) {
this.activePageIndex += 1;
} else {
this.activePageIndex = 0;
}
this.smoothScrollTo(this.getActivePageOffset(), 0);
}
public int getChildSpacing() {
return this.childSpacing;
}
public void setChildSpacing(int spacing) {
this.childSpacing = spacing;
}
}