|
|
|
@ -19,12 +19,15 @@
|
|
|
|
|
|
|
|
|
|
package org.isoron.uhabits.views;
|
|
|
|
|
|
|
|
|
|
import android.animation.ValueAnimator;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.support.v4.view.MotionEventCompat;
|
|
|
|
|
import android.view.GestureDetector;
|
|
|
|
|
import android.view.MotionEvent;
|
|
|
|
|
import android.view.View;
|
|
|
|
|
import android.widget.Scroller;
|
|
|
|
|
|
|
|
|
|
public abstract class ScrollableDataView extends View
|
|
|
|
|
public abstract class ScrollableDataView extends View implements GestureDetector.OnGestureListener,
|
|
|
|
|
ValueAnimator.AnimatorUpdateListener
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
protected int dataOffset;
|
|
|
|
@ -32,74 +35,105 @@ public abstract class ScrollableDataView extends View
|
|
|
|
|
protected int columnWidth, columnHeight;
|
|
|
|
|
protected int headerHeight, footerHeight;
|
|
|
|
|
|
|
|
|
|
private float prevX, prevY;
|
|
|
|
|
private GestureDetector detector;
|
|
|
|
|
private Scroller scroller;
|
|
|
|
|
private ValueAnimator scrollAnimator;
|
|
|
|
|
|
|
|
|
|
public ScrollableDataView(Context context)
|
|
|
|
|
{
|
|
|
|
|
super(context);
|
|
|
|
|
|
|
|
|
|
detector = new GestureDetector(context, this);
|
|
|
|
|
scroller = new Scroller(context, null, true);
|
|
|
|
|
scrollAnimator = ValueAnimator.ofFloat(0, 1);
|
|
|
|
|
scrollAnimator.addUpdateListener(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected abstract void fetchData();
|
|
|
|
|
|
|
|
|
|
protected boolean move(float dx)
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onTouchEvent(MotionEvent event)
|
|
|
|
|
{
|
|
|
|
|
int newDataOffset = dataOffset + (int) (dx / columnWidth);
|
|
|
|
|
newDataOffset = Math.max(0, newDataOffset);
|
|
|
|
|
return detector.onTouchEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (newDataOffset != dataOffset)
|
|
|
|
|
{
|
|
|
|
|
dataOffset = newDataOffset;
|
|
|
|
|
fetchData();
|
|
|
|
|
invalidate();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else return false;
|
|
|
|
|
@Override
|
|
|
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
|
|
|
|
{
|
|
|
|
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
|
|
|
setMeasuredDimension(getMeasuredWidth(), columnHeight + headerHeight + footerHeight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onTouchEvent(MotionEvent event)
|
|
|
|
|
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
|
|
|
|
{
|
|
|
|
|
int action = event.getAction();
|
|
|
|
|
super.onSizeChanged(w, h, oldw, oldh);
|
|
|
|
|
nColumns = w / columnWidth;
|
|
|
|
|
fetchData();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int pointerIndex = MotionEventCompat.getActionIndex(event);
|
|
|
|
|
final float x = MotionEventCompat.getX(event, pointerIndex);
|
|
|
|
|
final float y = MotionEventCompat.getY(event, pointerIndex);
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onDown(MotionEvent e)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (action == MotionEvent.ACTION_DOWN)
|
|
|
|
|
{
|
|
|
|
|
prevX = x;
|
|
|
|
|
prevY = y;
|
|
|
|
|
}
|
|
|
|
|
@Override
|
|
|
|
|
public void onShowPress(MotionEvent e)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (action == MotionEvent.ACTION_MOVE)
|
|
|
|
|
{
|
|
|
|
|
float dx = x - prevX;
|
|
|
|
|
float dy = y - prevY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Math.abs(dy) > Math.abs(dx)) return false;
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onSingleTapUp(MotionEvent e)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx, float dy)
|
|
|
|
|
{
|
|
|
|
|
if(Math.abs(dx) > Math.abs(dy))
|
|
|
|
|
getParent().requestDisallowInterceptTouchEvent(true);
|
|
|
|
|
if (move(dx))
|
|
|
|
|
{
|
|
|
|
|
prevX = x;
|
|
|
|
|
prevY = y;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scroller.startScroll(scroller.getCurrX(), scroller.getCurrY(), (int) -dx, (int) dy, 0);
|
|
|
|
|
scroller.computeScrollOffset();
|
|
|
|
|
dataOffset = Math.max(0, scroller.getCurrX() / columnWidth);
|
|
|
|
|
postInvalidate();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
|
|
|
|
public void onLongPress(MotionEvent e)
|
|
|
|
|
{
|
|
|
|
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
|
|
|
setMeasuredDimension(getMeasuredWidth(), columnHeight + headerHeight + footerHeight);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
|
|
|
|
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
|
|
|
|
|
{
|
|
|
|
|
super.onSizeChanged(w, h, oldw, oldh);
|
|
|
|
|
nColumns = w / columnWidth;
|
|
|
|
|
fetchData();
|
|
|
|
|
scroller.fling(scroller.getCurrX(), scroller.getCurrY(), (int) velocityX / 2, 0, 0, 100000,
|
|
|
|
|
0, 0);
|
|
|
|
|
invalidate();
|
|
|
|
|
|
|
|
|
|
scrollAnimator.setDuration(scroller.getDuration());
|
|
|
|
|
scrollAnimator.start();
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onAnimationUpdate(ValueAnimator animation)
|
|
|
|
|
{
|
|
|
|
|
if (!scroller.isFinished())
|
|
|
|
|
{
|
|
|
|
|
scroller.computeScrollOffset();
|
|
|
|
|
dataOffset = Math.max(0, scroller.getCurrX() / columnWidth);
|
|
|
|
|
postInvalidate();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
scrollAnimator.cancel();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|