Skip to content

Commit d5c188f

Browse files
author
Richard Ratmansky
committed
Fling with over scroll and edge effect
1 parent 941a974 commit d5c188f

File tree

2 files changed

+136
-44
lines changed

2 files changed

+136
-44
lines changed

CollectionViews2/src/org/freeflow/core/Container.java

Lines changed: 135 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.freeflow.utils.ViewUtils;
1111

1212
import android.content.Context;
13+
import android.graphics.Canvas;
1314
import android.graphics.Rect;
1415
import android.support.v4.util.SimpleArrayMap;
1516
import android.util.AttributeSet;
@@ -25,7 +26,8 @@
2526
import android.view.View;
2627
import android.view.ViewConfiguration;
2728
import android.widget.Checkable;
28-
import android.widget.Scroller;
29+
import android.widget.EdgeEffect;
30+
import android.widget.OverScroller;
2931

3032
public class Container extends AbsLayoutContainer {
3133

@@ -64,9 +66,11 @@ public class Container extends AbsLayoutContainer {
6466
private Runnable mPendingCheckForTap;
6567
private Runnable mPendingCheckForLongPress;
6668

67-
private Scroller scroller;
69+
private OverScroller scroller;
6870
private boolean flingStarted = false;
6971

72+
private EdgeEffect mLeftEdge, mRightEdge, mTopEdge, mBottomEdge;
73+
7074
// This flag controls whether onTap/onLongPress/onTouch trigger
7175
// the ActionMode
7276
// private boolean mDataChanged = false;
@@ -127,13 +131,20 @@ protected void init(Context context) {
127131
// usedViews = new HashMap<Object, ItemProxy>();
128132
// usedHeaderViews = new HashMap<Object, ItemProxy>();
129133

134+
setWillNotDraw(false);
135+
130136
viewpool = new ViewPool();
131137
frames = new HashMap<Object, ItemProxy>();
132138

133139
maxFlingVelocity = ViewConfiguration.get(context).getScaledMaximumFlingVelocity();
134140
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
135-
scroller = new Scroller(context);
136-
// scroller.setFriction(ViewConfiguration.getScrollFriction());
141+
142+
// TODO: create Scroller vars
143+
scroller = new OverScroller(context);
144+
mLeftEdge = new EdgeEffect(context);
145+
mRightEdge = new EdgeEffect(context);
146+
mTopEdge = new EdgeEffect(context);
147+
mBottomEdge = new EdgeEffect(context);
137148

138149
}
139150

@@ -151,6 +162,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
151162
if (beforeWidth != afterWidth || beforeHeight != afterHeight || markLayoutDirty) {
152163
computeLayout(afterWidth, afterHeight);
153164
}
165+
154166
}
155167

156168
public void computeLayout(int w, int h) {
@@ -226,7 +238,9 @@ private void prepareViewForAddition(View view, ItemProxy proxy) {
226238
protected void onLayout(boolean changed, int l, int t, int r, int b) {
227239
// Log.d(TAG, "== onLayout ==");
228240
// mDataChanged = false;
241+
229242
dispatchLayoutComplete();
243+
230244
}
231245

232246
private void doLayout(ItemProxy proxy) {
@@ -561,8 +575,8 @@ public boolean onTouchEvent(MotionEvent event) {
561575

562576
if (event.getAction() == MotionEvent.ACTION_DOWN) {
563577

564-
scroller.abortAnimation();
565-
578+
scroller.forceFinished(true);
579+
566580
beginTouchAt = ViewUtils.getItemAt(frames, (int) (viewPortX + event.getX()),
567581
(int) (viewPortY + event.getY()));
568582

@@ -603,7 +617,17 @@ public boolean onTouchEvent(MotionEvent event) {
603617
}
604618

605619
if (mTouchMode == TOUCH_MODE_SCROLL) {
606-
moveScreen(event.getX() - deltaX, event.getY() - deltaY);
620+
moveScreen(event.getX() - deltaX, event.getY() - deltaY, false);
621+
622+
float max = layout.getContentWidth() - getWidth() - 200;
623+
Log.d(TAG, "viewport = " + viewPortX + " max = " + max);
624+
if (viewPortX > max) {
625+
float val = ((float) viewPortX - max) / 200F;
626+
Log.d(TAG, "val= " + val);
627+
628+
// mTopEdge.onPull(val);
629+
}
630+
607631
deltaX = event.getX();
608632
deltaY = event.getY();
609633
}
@@ -624,6 +648,9 @@ public boolean onTouchEvent(MotionEvent event) {
624648
return true;
625649

626650
} else if (event.getAction() == MotionEvent.ACTION_UP) {
651+
652+
// mTopEdge.onRelease();
653+
627654
if (mTouchMode == TOUCH_MODE_SCROLL) {
628655
mVelocityTracker.computeCurrentVelocity(1000, maxFlingVelocity);
629656

@@ -637,36 +664,16 @@ public boolean onTouchEvent(MotionEvent event) {
637664
if (Math.abs(mVelocityTracker.getXVelocity()) > 100 || Math.abs(mVelocityTracker.getYVelocity()) > 100) {
638665

639666
// TODO: add scroller call here...
640-
// scroller.forceFinished(true);
641-
// scroller.abortAnimation();
667+
// scroller.forceFinished(true);
668+
// scroller.abortAnimation();
642669

643670
flingStarted = true;
644671
scroller.fling(viewPortX, viewPortY, -(int) mVelocityTracker.getXVelocity(),
645672
-(int) mVelocityTracker.getYVelocity(), 0, layout.getContentWidth() - getWidth(), 0,
646-
layout.getContentHeight() - getHeight());
673+
layout.getContentHeight() - getHeight(), 300, 300);
647674

648675
post(scrollRunnable);
649676

650-
// final float velocityX = mVelocityTracker.getXVelocity();
651-
// final float velocityY = mVelocityTracker.getYVelocity();
652-
// ValueAnimator animator = ValueAnimator.ofFloat(1, 0);
653-
// animator.addUpdateListener(new AnimatorUpdateListener() {
654-
//
655-
// @Override
656-
// public void onAnimationUpdate(ValueAnimator animation) {
657-
// int translateX = (int) ((1 -
658-
// animation.getAnimatedFraction()) * velocityX / 350);
659-
// int translateY = (int) ((1 -
660-
// animation.getAnimatedFraction()) * velocityY / 350);
661-
//
662-
// moveScreen(translateX, translateY);
663-
//
664-
// }
665-
// });
666-
//
667-
// animator.setDuration(500);
668-
// animator.start();
669-
670677
}
671678
mTouchMode = TOUCH_MODE_REST;
672679
Log.d(TAG, "Setting to rest");
@@ -718,7 +725,7 @@ public ItemProxy getSelectedItemProxy() {
718725
return selectedItemProxy;
719726
}
720727

721-
//TODO: scroll runnable
728+
// TODO: scroll runnable
722729
private Runnable scrollRunnable = new Runnable() {
723730

724731
@Override
@@ -730,14 +737,37 @@ public void run() {
730737

731738
boolean more = scroller.computeScrollOffset();
732739

740+
if ((flingStarted || mLeftEdge.isFinished()) && viewPortX < 0 && layout.horizontalDragEnabled()) {
741+
mLeftEdge.finish();
742+
mLeftEdge.onAbsorb((int) scroller.getCurrVelocity());
743+
}
744+
745+
if ((flingStarted || mRightEdge.isFinished()) && viewPortX > layout.getContentWidth() - getMeasuredWidth()
746+
&& layout.horizontalDragEnabled()) {
747+
mRightEdge.finish();
748+
mRightEdge.onAbsorb((int) scroller.getCurrVelocity());
749+
}
750+
751+
if ((flingStarted || mTopEdge.isFinished()) && viewPortY < 0 && layout.verticalDragEnabled()) {
752+
mTopEdge.finish();
753+
mTopEdge.onAbsorb((int) scroller.getCurrVelocity());
754+
}
755+
756+
if ((flingStarted || mBottomEdge.isFinished())
757+
&& viewPortY > layout.getContentHeight() - getMeasuredHeight() && layout.verticalDragEnabled()) {
758+
mBottomEdge.finish();
759+
mBottomEdge.onAbsorb((int) scroller.getCurrVelocity());
760+
}
761+
733762
if (flingStarted) {
734763
flingStarted = false;
735764
scrollDeltaX = scroller.getCurrX();
736765
scrollDeltaY = scroller.getCurrY();
737766
}
738767

739-
Log.d("scrolling", "vel = " + scroller.getCurrVelocity() + ", cur x = " + scroller.getCurrX()
740-
+ ", cur y = " + scroller.getCurrY() + ", vp x = " + viewPortX);
768+
// Log.d("scrolling", "vel = " + scroller.getCurrVelocity() +
769+
// ", cur x = " + scroller.getCurrX()
770+
// + ", cur y = " + scroller.getCurrY() + ", vp x = " + viewPortX);
741771
int x = scroller.getCurrX();
742772
int y = scroller.getCurrY();
743773

@@ -747,15 +777,15 @@ public void run() {
747777
scrollDeltaX = x;
748778
scrollDeltaY = y;
749779

750-
moveScreen(-diffx, -diffy);
780+
moveScreen(-diffx, -diffy, true);
751781

752782
if (more) {
753783
post(scrollRunnable);
754784
}
755785
}
756786
};
757787

758-
private void moveScreen(float movementX, float movementY) {
788+
private void moveScreen(float movementX, float movementY, boolean fling) {
759789

760790
if (layout.horizontalDragEnabled()) {
761791
viewPortX = (int) (viewPortX - movementX);
@@ -772,16 +802,17 @@ private void moveScreen(float movementX, float movementY) {
772802
scrollableWidth = layout.getContentWidth() - getWidth();
773803
scrollableHeight = layout.getContentHeight() - getHeight();
774804

775-
if (viewPortX < 0)
776-
viewPortX = 0;
777-
else if (viewPortX > scrollableWidth)
778-
viewPortX = scrollableWidth;
779-
780-
if (viewPortY < 0)
781-
viewPortY = 0;
782-
else if (viewPortY > scrollableHeight)
783-
viewPortY = scrollableHeight;
805+
if (!fling) {
806+
if (viewPortX < 0)
807+
viewPortX = 0;
808+
else if (viewPortX > scrollableWidth)
809+
viewPortX = scrollableWidth;
784810

811+
if (viewPortY < 0)
812+
viewPortY = 0;
813+
else if (viewPortY > scrollableHeight)
814+
viewPortY = scrollableHeight;
815+
}
785816
HashMap<? extends Object, ItemProxy> oldFrames = frames;
786817

787818
frames = new HashMap<Object, ItemProxy>(layout.getItemProxies(viewPortX, viewPortY));
@@ -805,6 +836,66 @@ else if (viewPortY > scrollableHeight)
805836

806837
}
807838

839+
@Override
840+
protected void onDraw(Canvas canvas) {
841+
super.onDraw(canvas);
842+
843+
boolean needsInvalidate = false;
844+
845+
final int height = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
846+
final int width = getMeasuredWidth();
847+
848+
if (!mLeftEdge.isFinished()) {
849+
// Log.d("EdgeView", "edge not finished");
850+
final int restoreCount = canvas.save();
851+
852+
canvas.rotate(270);
853+
canvas.translate(-height + getPaddingTop(), 0);// width);
854+
mLeftEdge.setSize(height, width);
855+
856+
needsInvalidate = mLeftEdge.draw(canvas);
857+
canvas.restoreToCount(restoreCount);
858+
}
859+
860+
if (!mTopEdge.isFinished()) {
861+
// Log.d("EdgeView", "edge not finished");
862+
final int restoreCount = canvas.save();
863+
864+
mTopEdge.setSize(width, height);
865+
866+
needsInvalidate = mTopEdge.draw(canvas);
867+
canvas.restoreToCount(restoreCount);
868+
}
869+
870+
if (!mRightEdge.isFinished()) {
871+
// Log.d("EdgeView", "edge not finished");
872+
final int restoreCount = canvas.save();
873+
874+
canvas.rotate(90);
875+
canvas.translate(0, -width);// width);
876+
mRightEdge.setSize(height, width);
877+
878+
needsInvalidate = mRightEdge.draw(canvas);
879+
canvas.restoreToCount(restoreCount);
880+
}
881+
882+
if (!mBottomEdge.isFinished()) {
883+
// Log.d("EdgeView", "edge not finished");
884+
final int restoreCount = canvas.save();
885+
886+
canvas.rotate(180);
887+
canvas.translate(-width + getPaddingTop(), -height);
888+
mBottomEdge.setSize(height, width);
889+
890+
needsInvalidate = mBottomEdge.draw(canvas);
891+
canvas.restoreToCount(restoreCount);
892+
}
893+
894+
if (needsInvalidate)
895+
postInvalidateOnAnimation();
896+
897+
}
898+
808899
protected void returnItemToPoolIfNeeded(ItemProxy proxy) {
809900
View v = proxy.view;
810901
v.setTranslationX(0);

examples/PhotoGrid/src/org/freeflow/examples/freeflowphotogrid/MainActivity.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ public View getViewForSection(int section, int position, View convertView, ViewG
166166

167167
tv.setFocusable(false);
168168
tv.setBackgroundResource(R.drawable.orange);
169+
// tv.setAlpha(.25f);
169170
// button.setOnTouchListener(MainActivity.this);
170171
tv.setText("s" + section + " p" + position);
171172

0 commit comments

Comments
 (0)