diff --git a/build.gradle b/build.gradle index 7efab93..186650d 100644 --- a/build.gradle +++ b/build.gradle @@ -3,15 +3,12 @@ buildscript { repositories { jcenter() - maven { - url "https://jcenter.bintray.com" - } } dependencies { classpath 'com.android.tools.build:gradle:1.3.0' - classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0' - classpath 'com.github.dcendents:android-maven-plugin:1.2' + classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.1' + classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/library/src/main/java/com/baoyz/widget/ArcDrawable.java b/library/src/main/java/com/baoyz/widget/ArcDrawable.java index 72a2fb2..90e7628 100644 --- a/library/src/main/java/com/baoyz/widget/ArcDrawable.java +++ b/library/src/main/java/com/baoyz/widget/ArcDrawable.java @@ -32,7 +32,7 @@ class ArcDrawable extends RefreshDrawable{ private int mLevel; ArcDrawable(Context context, PullRefreshLayout layout) { - super(context, layout); + super(layout); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(Color.RED); } @@ -110,7 +110,7 @@ protected void onBoundsChange(Rect bounds) { } @Override - public void draw(Canvas canvas) { + public void onDraw(Canvas canvas) { canvas.save(); // canvas.translate(0, mTop); drawRing(canvas); diff --git a/library/src/main/java/com/baoyz/widget/CirclesDrawable.java b/library/src/main/java/com/baoyz/widget/CirclesDrawable.java index d495aee..c1ee1d3 100644 --- a/library/src/main/java/com/baoyz/widget/CirclesDrawable.java +++ b/library/src/main/java/com/baoyz/widget/CirclesDrawable.java @@ -49,7 +49,7 @@ class CirclesDrawable extends RefreshDrawable implements Runnable { private Rect mBounds; public CirclesDrawable(Context context, PullRefreshLayout layout) { - super(context, layout); + super(layout); } @Override @@ -198,7 +198,7 @@ private void resetColor(ProgressStates currentState) { } @Override - public void draw(Canvas canvas) { + public void onDraw(Canvas canvas) { if (mCurrentState != null) { canvas.save(); canvas.translate(mBounds.width() / 2 - mDrawWidth / 2, mTop); diff --git a/library/src/main/java/com/baoyz/widget/MaterialDrawable.java b/library/src/main/java/com/baoyz/widget/MaterialDrawable.java index c67661b..b979637 100644 --- a/library/src/main/java/com/baoyz/widget/MaterialDrawable.java +++ b/library/src/main/java/com/baoyz/widget/MaterialDrawable.java @@ -59,6 +59,8 @@ class MaterialDrawable extends RefreshDrawable implements Animatable { private static final Interpolator END_CURVE_INTERPOLATOR = new EndCurveInterpolator(); private static final Interpolator START_CURVE_INTERPOLATOR = new StartCurveInterpolator(); private static final Interpolator EASE_INTERPOLATOR = new AccelerateDecelerateInterpolator(); + private Rect mRect; + private boolean isRunning; @Retention(RetentionPolicy.CLASS) @IntDef({LARGE, DEFAULT}) @@ -151,7 +153,7 @@ class MaterialDrawable extends RefreshDrawable implements Animatable { private int mDiameter; public MaterialDrawable(Context context, PullRefreshLayout parent) { - super(context, parent); + super(parent); mParent = parent; mResources = context.getResources(); @@ -205,8 +207,8 @@ public OvalShadow(int shadowRadius, int circleDiameter) { @Override public void draw(Canvas canvas, Paint paint) { - final int x = MaterialDrawable.this.getBounds().centerX(); - final int y = MaterialDrawable.this.getBounds().centerY(); + final int x = mRect.centerX(); + final int y = mRect.centerY(); canvas.drawCircle(x, y, (mCircleDiameter / 2 + mShadowRadius), mShadowPaint); canvas.drawCircle(x, y, (mCircleDiameter / 2), paint); @@ -287,13 +289,12 @@ public void setBackgroundColor(int color) { public void setPercent(float percent) { if (percent < .4f) return; - percent = (percent - .4f) / .6f; + percent = (percent - .4f) / .6f * 1.2f; setAlpha((int) (MAX_ALPHA * percent)); showArrow(true); - float strokeStart = ((percent) * .8f); - setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, strokeStart)); + setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, percent)); setArrowScale(Math.min(1f, percent)); - float rotation = percent < .8f ? 0 : (percent - .8f) / .2f * .25f; + float rotation = percent > MAX_PROGRESS_ANGLE ? (percent - MAX_PROGRESS_ANGLE) * .9f : 0; setProgressRotation(rotation); } @@ -326,8 +327,8 @@ public void offsetTopAndBottom(int offset) { // } @Override - public void draw(Canvas c) { - Rect bounds = getBounds(); + public void onDraw(Canvas c) { + Rect bounds = mRect; final int saveCount = c.save(); c.translate(0, mTop); mCircle.draw(c); @@ -340,14 +341,16 @@ public void draw(Canvas c) { @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); - + int w = bounds.width(); + int top = bounds.top; + mRect = new Rect(w / 2 - mDiameter / 2, top, w / 2 + mDiameter / 2, mDiameter + top); } - @Override - public void setBounds(int left, int top, int right, int bottom) { - int w = right - left; - super.setBounds(w / 2 - mDiameter / 2, top, w / 2 + mDiameter / 2, mDiameter + top); - } +// @Override +// public void setBounds(int left, int top, int right, int bottom) { +// int w = right - left; +// super.setBounds(w / 2 - mDiameter / 2, top, w / 2 + mDiameter / 2, mDiameter + top); +// } private int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics()); @@ -385,19 +388,12 @@ public int getOpacity() { @Override public boolean isRunning() { - final ArrayList animators = mAnimators; - final int N = animators.size(); - for (int i = 0; i < N; i++) { - final Animation animator = animators.get(i); - if (animator.hasStarted() && !animator.hasEnded()) { - return true; - } - } - return false; + return isRunning; } @Override public void start() { + isRunning = true; mAnimation.reset(); mRing.storeOriginals(); // Already showing some part of the ring @@ -417,6 +413,7 @@ public void stop() { mRing.setShowArrow(false); mRing.setColorIndex(0); mRing.resetOriginals(); + isRunning = false; } private void setupAnimators() { @@ -425,6 +422,10 @@ private void setupAnimators() { public void applyTransformation(float interpolatedTime, Transformation t) { // shrink back down and complete a full rotation before starting other circles // Rotation goes between [0..1]. + if (!isRunning) { + mParent.clearAnimation(); + return; + } float targetRotation = (float) (Math.floor(ring.getStartingRotation() / MAX_PROGRESS_ARC) + 1f); final float startTrim = ring.getStartingStartTrim() @@ -462,6 +463,10 @@ public void onAnimationRepeat(Animation animation) { public void applyTransformation(float interpolatedTime, Transformation t) { // The minProgressArc is calculated from 0 to create an angle that // matches the stroke width. + if (!isRunning) { + mParent.clearAnimation(); + return; + } final float minProgressArc = (float) Math.toRadians(ring.getStrokeWidth() / (2 * Math.PI * ring.getCenterRadius())); final float startingEndTrim = ring.getStartingEndTrim(); diff --git a/library/src/main/java/com/baoyz/widget/PullRefreshLayout.java b/library/src/main/java/com/baoyz/widget/PullRefreshLayout.java index 5fcefc0..1410a9f 100644 --- a/library/src/main/java/com/baoyz/widget/PullRefreshLayout.java +++ b/library/src/main/java/com/baoyz/widget/PullRefreshLayout.java @@ -25,6 +25,8 @@ */ public class PullRefreshLayout extends ViewGroup { + private static final String TAG = "PRL"; + private static final float DECELERATE_INTERPOLATION_FACTOR = 2f; private static final int DRAG_MAX_DISTANCE = 64; private static final int INVALID_POINTER = -1; @@ -36,6 +38,10 @@ public class PullRefreshLayout extends ViewGroup { public static final int STYLE_RING = 3; public static final int STYLE_SMARTISAN = 4; + public static final int DIRECTION_UP = -1; + public static final int DIRECTION_DOWN = 1; + public static final int DIRECTION_NONE = 0; + private View mTarget; private ImageView mRefreshView; private Interpolator mDecelerateInterpolator; @@ -58,6 +64,7 @@ public class PullRefreshLayout extends ViewGroup { private int mInitialOffsetTop; private boolean mDispatchTargetTouchDown; private float mDragPercent; + private int mScrollDirection; public PullRefreshLayout(Context context) { this(context, null); @@ -171,7 +178,7 @@ private void ensureTarget() { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - if (!isEnabled() || (canChildScrollUp() && !mRefreshing)) { + if (!isEnabled()) { return false; } @@ -179,9 +186,9 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { switch (action) { case MotionEvent.ACTION_DOWN: - if (!mRefreshing) { - setTargetOffsetTop(0, true); - } +// if (!mRefreshing) { +// setTargetOffsetTop(0, true); +// } mActivePointerId = MotionEventCompat.getPointerId(ev, 0); mIsBeingDragged = false; final float initialMotionY = getMotionEventY(ev, mActivePointerId); @@ -201,11 +208,21 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { if (y == -1) { return false; } - final float yDiff = y - mInitialMotionY; + float yDiff = y - mInitialMotionY; if (mRefreshing) { + yDiff = mScrollDirection == DIRECTION_UP ? y - mInitialMotionY : mInitialMotionY - y; mIsBeingDragged = !(yDiff < 0 && mCurrentOffsetTop <= 0); - } else if (yDiff > mTouchSlop && !mIsBeingDragged) { - mIsBeingDragged = true; + } else if (Math.abs(yDiff) > mTouchSlop && !mIsBeingDragged) { + if (yDiff > 0) { + // scroll up + mIsBeingDragged = !canChildScrollUp(); + mScrollDirection = DIRECTION_UP; + } else { + // scroll down + mIsBeingDragged = !canChildScrollDown(); + mScrollDirection = DIRECTION_DOWN; + } + mRefreshDrawable.setDirection(mScrollDirection); } break; case MotionEvent.ACTION_UP: @@ -238,11 +255,11 @@ public boolean onTouchEvent(MotionEvent ev) { } final float y = MotionEventCompat.getY(ev, pointerIndex); - final float yDiff = y - mInitialMotionY; + final float yDiff = mScrollDirection == DIRECTION_UP ? y - mInitialMotionY : mInitialMotionY - y; int targetY; if (mRefreshing) { targetY = (int) (mInitialOffsetTop + yDiff); - if (canChildScrollUp()) { + if (canChildScroll()) { targetY = -1; mInitialMotionY = y; mInitialOffsetTop = 0; @@ -322,9 +339,9 @@ public boolean onTouchEvent(MotionEvent ev) { } final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); final float y = MotionEventCompat.getY(ev, pointerIndex); - final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE; + final float overScrollTop = (mScrollDirection == DIRECTION_UP ? y - mInitialMotionY : mInitialMotionY - y) * DRAG_RATE; mIsBeingDragged = false; - if (overscrollTop > mTotalDragDistance) { + if (overScrollTop > mTotalDragDistance) { setRefreshing(true, true); } else { mRefreshing = false; @@ -338,6 +355,72 @@ public boolean onTouchEvent(MotionEvent ev) { return true; } + private void setTargetOffsetTop(int offset, boolean requiresUpdate) { + if (mScrollDirection == DIRECTION_DOWN) { + mTarget.offsetTopAndBottom(-offset); + mRefreshDrawable.offsetTopAndBottom(offset); + } else { + mTarget.offsetTopAndBottom(offset); + mRefreshDrawable.offsetTopAndBottom(offset); + } + mCurrentOffsetTop = getTargetTop(); + + if (requiresUpdate && android.os.Build.VERSION.SDK_INT < 11) { + invalidate(); + } + } + + private void onSecondaryPointerUp(MotionEvent ev) { + final int pointerIndex = MotionEventCompat.getActionIndex(ev); + final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); + if (pointerId == mActivePointerId) { + final int newPointerIndex = pointerIndex == 0 ? 1 : 0; + mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); + } + } + + private float getMotionEventY(MotionEvent ev, int activePointerId) { + final int index = MotionEventCompat.findPointerIndex(ev, activePointerId); + if (index < 0) { + return -1; + } + return MotionEventCompat.getY(ev, index); + } + + private boolean canChildScroll() { + return mScrollDirection == DIRECTION_UP ? canChildScrollUp() : canChildScrollDown(); + } + + private boolean canChildScrollUp() { + if (android.os.Build.VERSION.SDK_INT < 14) { + if (mTarget instanceof AbsListView) { + final AbsListView absListView = (AbsListView) mTarget; + return absListView.getChildCount() > 0 + && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0) + .getTop() < absListView.getPaddingTop()); + } else { + return mTarget.getScrollY() > 0; + } + } else { + return ViewCompat.canScrollVertically(mTarget, DIRECTION_UP); + } + } + + private boolean canChildScrollDown() { + if (android.os.Build.VERSION.SDK_INT < 14) { + if (mTarget instanceof AbsListView) { + final AbsListView absListView = (AbsListView) mTarget; + return absListView.getChildCount() > 0 + && (absListView.getLastVisiblePosition() < (absListView.getCount() - 1) || absListView.getChildAt((absListView.getCount() - 1)) + .getBottom() < absListView.getPaddingBottom()); + } else { + return ViewCompat.canScrollVertically(mTarget, DIRECTION_DOWN); + } + } else { + return ViewCompat.canScrollVertically(mTarget, DIRECTION_DOWN); + } + } + public void setDurations(int durationToStartPosition, int durationToCorrectPosition) { mDurationToStartPosition = durationToStartPosition; mDurationToCorrectPosition = durationToCorrectPosition; @@ -375,20 +458,28 @@ public void applyTransformation(float interpolatedTime, Transformation t) { public void applyTransformation(float interpolatedTime, Transformation t) { int endTarget = mSpinnerFinalOffset; int targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime)); - int offset = targetTop - mTarget.getTop(); + int offset = targetTop - getTargetTop(); setTargetOffsetTop(offset, false /* requires update */); } }; private void moveToStart(float interpolatedTime) { int targetTop = mFrom - (int) (mFrom * interpolatedTime); - int offset = targetTop - mTarget.getTop(); + int offset = targetTop - getTargetTop(); setTargetOffsetTop(offset, false); mRefreshDrawable.setPercent(mDragPercent * (1 - interpolatedTime)); } + private int getTargetTop() { + return mScrollDirection == DIRECTION_UP ? mTarget.getTop() : -mTarget.getTop(); +// return mTarget.getTop(); + } + public void setRefreshing(boolean refreshing) { if (mRefreshing != refreshing) { + if (mScrollDirection == DIRECTION_NONE) { + mScrollDirection = DIRECTION_UP; + } setRefreshing(refreshing, false /* notify */); } } @@ -423,7 +514,7 @@ public void onAnimationEnd(Animation animation) { mRefreshDrawable.start(); if (mNotify) { if (mListener != null) { - mListener.onRefresh(); + mListener.onRefresh(mScrollDirection); } } } else { @@ -431,7 +522,7 @@ public void onAnimationEnd(Animation animation) { mRefreshView.setVisibility(View.GONE); animateOffsetToStartPosition(); } - mCurrentOffsetTop = mTarget.getTop(); + mCurrentOffsetTop = getTargetTop(); } }; @@ -449,52 +540,10 @@ public void onAnimationRepeat(Animation animation) { public void onAnimationEnd(Animation animation) { // mRefreshDrawable.stop(); mRefreshView.setVisibility(View.GONE); - mCurrentOffsetTop = mTarget.getTop(); + mCurrentOffsetTop = getTargetTop(); } }; - private void onSecondaryPointerUp(MotionEvent ev) { - final int pointerIndex = MotionEventCompat.getActionIndex(ev); - final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); - if (pointerId == mActivePointerId) { - final int newPointerIndex = pointerIndex == 0 ? 1 : 0; - mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); - } - } - - private float getMotionEventY(MotionEvent ev, int activePointerId) { - final int index = MotionEventCompat.findPointerIndex(ev, activePointerId); - if (index < 0) { - return -1; - } - return MotionEventCompat.getY(ev, index); - } - - private void setTargetOffsetTop(int offset, boolean requiresUpdate) { -// mRefreshView.bringToFront(); - mTarget.offsetTopAndBottom(offset); - mCurrentOffsetTop = mTarget.getTop(); - mRefreshDrawable.offsetTopAndBottom(offset); - if (requiresUpdate && android.os.Build.VERSION.SDK_INT < 11) { - invalidate(); - } - } - - private boolean canChildScrollUp() { - if (android.os.Build.VERSION.SDK_INT < 14) { - if (mTarget instanceof AbsListView) { - final AbsListView absListView = (AbsListView) mTarget; - return absListView.getChildCount() > 0 - && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0) - .getTop() < absListView.getPaddingTop()); - } else { - return mTarget.getScrollY() > 0; - } - } else { - return ViewCompat.canScrollVertically(mTarget, -1); - } - } - @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { @@ -513,6 +562,10 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { mRefreshView.layout(left, top, left + width - right, top + height - bottom); } + public int getScrollDirection() { + return mScrollDirection; + } + private int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics()); } @@ -521,7 +574,27 @@ public void setOnRefreshListener(OnRefreshListener listener) { mListener = listener; } - public static interface OnRefreshListener { - public void onRefresh(); + public interface OnRefreshListener { + void onRefresh(int direction); + } + + public static class SimpleOnRefreshListener implements OnRefreshListener { + + @Override + public void onRefresh(int direction) { + if (direction == DIRECTION_UP) { + onRefresh(); + } else { + onRefreshMore(); + } + } + + public void onRefresh() { + + } + + public void onRefreshMore() { + + } } } diff --git a/library/src/main/java/com/baoyz/widget/RefreshDrawable.java b/library/src/main/java/com/baoyz/widget/RefreshDrawable.java index 5acbf0c..baac3e6 100644 --- a/library/src/main/java/com/baoyz/widget/RefreshDrawable.java +++ b/library/src/main/java/com/baoyz/widget/RefreshDrawable.java @@ -1,8 +1,10 @@ package com.baoyz.widget; import android.content.Context; +import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; +import android.graphics.Rect; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; @@ -12,8 +14,9 @@ public abstract class RefreshDrawable extends Drawable implements Drawable.Callback, Animatable { private PullRefreshLayout mRefreshLayout; + private int mDirection; - public RefreshDrawable(Context context, PullRefreshLayout layout) { + public RefreshDrawable(PullRefreshLayout layout) { mRefreshLayout = layout; } @@ -27,8 +30,22 @@ public PullRefreshLayout getRefreshLayout(){ public abstract void setPercent(float percent); public abstract void setColorSchemeColors(int[] colorSchemeColors); - public abstract void offsetTopAndBottom(int offset); + public void setDirection(int direction) { + mDirection = direction; + } + + @Override + public final void draw(Canvas canvas) { + int save = canvas.save(); + if (mDirection == PullRefreshLayout.DIRECTION_DOWN) { + canvas.rotate(180, getBounds().centerX(), getBounds().centerY()); + } + onDraw(canvas); + canvas.restoreToCount(save); + } + + public abstract void onDraw(Canvas canvas); @Override public void invalidateDrawable(Drawable who) { diff --git a/library/src/main/java/com/baoyz/widget/RingDrawable.java b/library/src/main/java/com/baoyz/widget/RingDrawable.java index deabbc5..fb2fabf 100644 --- a/library/src/main/java/com/baoyz/widget/RingDrawable.java +++ b/library/src/main/java/com/baoyz/widget/RingDrawable.java @@ -29,7 +29,7 @@ class RingDrawable extends RefreshDrawable { private float mDegress; RingDrawable(Context context, PullRefreshLayout layout) { - super(context, layout); + super(layout); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(dp2px(3)); @@ -94,7 +94,7 @@ protected void onBoundsChange(Rect bounds) { } @Override - public void draw(Canvas canvas) { + public void onDraw(Canvas canvas) { canvas.save(); // canvas.translate(0, mTop); canvas.rotate(mDegress, mBounds.centerX(), mBounds.centerY()); diff --git a/library/src/main/java/com/baoyz/widget/SmartisanDrawable.java b/library/src/main/java/com/baoyz/widget/SmartisanDrawable.java index f2d61b4..f4dfeb7 100644 --- a/library/src/main/java/com/baoyz/widget/SmartisanDrawable.java +++ b/library/src/main/java/com/baoyz/widget/SmartisanDrawable.java @@ -26,6 +26,7 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; @@ -57,7 +58,7 @@ public class SmartisanDrawable extends RefreshDrawable { float mDegrees; public SmartisanDrawable(Context context, PullRefreshLayout layout) { - super(context, layout); + super(layout); mPaint.setAntiAlias(true); mPaint.setStrokeJoin(Paint.Join.ROUND); @@ -114,7 +115,7 @@ public boolean isRunning() { } @Override - public void draw(Canvas canvas) { + public void onDraw(Canvas canvas) { canvas.save(); diff --git a/library/src/main/java/com/baoyz/widget/WaterDropDrawable.java b/library/src/main/java/com/baoyz/widget/WaterDropDrawable.java index e1d9203..53dbbf1 100644 --- a/library/src/main/java/com/baoyz/widget/WaterDropDrawable.java +++ b/library/src/main/java/com/baoyz/widget/WaterDropDrawable.java @@ -40,7 +40,7 @@ private enum ProgressStates { } public WaterDropDrawable(Context context, PullRefreshLayout layout) { - super(context, layout); + super(layout); mPaint = new Paint(); mPaint.setColor(Color.BLUE); mPaint.setStyle(Paint.Style.FILL); @@ -53,7 +53,7 @@ public WaterDropDrawable(Context context, PullRefreshLayout layout) { } @Override - public void draw(Canvas canvas) { + public void onDraw(Canvas canvas) { canvas.save(); canvas.translate(0, mTop > 0 ? mTop : 0); diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index e733af8..6c60d01 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -8,7 +8,12 @@ - - + + + + + + + \ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle index c2f7056..3d9ec50 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 21 - buildToolsVersion "21.0.2" + compileSdkVersion 23 + buildToolsVersion "23.0.1" defaultConfig { applicationId "com.baoyz.pullrefreshlayout.sample" - minSdkVersion 8 + minSdkVersion 14 targetSdkVersion 21 versionCode 1 versionName "1.0" @@ -21,7 +21,11 @@ android { dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') - compile 'com.android.support:support-v4:21.0.0' - compile 'com.android.support:recyclerview-v7:21.0.0' + compile 'com.android.support:support-v4:23.1.0' + compile 'com.android.support:recyclerview-v7:23.1.0' + compile 'com.android.support:cardview-v7:23.1.0' compile project(':library') + compile 'com.squareup.retrofit:retrofit:2.0.0-beta2' + compile 'com.squareup.retrofit:converter-moshi:2.0.0-beta2' + compile 'com.squareup.picasso:picasso:2.5.2' } diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 17ce1df..2f6971b 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -2,13 +2,15 @@ + + @@ -16,9 +18,13 @@ - - - + + + + + diff --git a/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/DemoActivity.java b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/DemoActivity.java index 223a8d1..678f523 100644 --- a/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/DemoActivity.java +++ b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/DemoActivity.java @@ -5,7 +5,7 @@ import android.os.Bundle; import android.view.View; -import com.baoyz.widget.PullRefreshLayout; +import com.baoyz.pullrefreshlayout.sample.gank.GankActivity; public class DemoActivity extends Activity { @@ -29,4 +29,9 @@ public void onScrollViewClick(View view) { startActivity(new Intent(this, ScrollViewActivity.class)); } + public void onGankDemoClick(View view) { + // Content from http://gank.io + startActivity(new Intent(this, GankActivity.class)); + } + } diff --git a/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/ListViewActivity.java b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/ListViewActivity.java index 06db9f1..c405ca1 100644 --- a/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/ListViewActivity.java +++ b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/ListViewActivity.java @@ -34,7 +34,7 @@ protected void onCreate(Bundle savedInstanceState) { layout = (PullRefreshLayout) findViewById(R.id.swipeRefreshLayout); layout.setOnRefreshListener(new PullRefreshLayout.OnRefreshListener() { @Override - public void onRefresh() { + public void onRefresh(int direction) { layout.postDelayed(new Runnable() { @Override public void run() { diff --git a/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/RecyclerViewActivity.java b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/RecyclerViewActivity.java index af928fa..7d87b10 100644 --- a/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/RecyclerViewActivity.java +++ b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/RecyclerViewActivity.java @@ -5,6 +5,7 @@ import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -23,7 +24,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_recycler_view); - RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView); + final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(this)); String[] array = new String[50]; for (int i = 0; i < array.length; i++) { @@ -34,7 +35,7 @@ protected void onCreate(Bundle savedInstanceState) { layout = (PullRefreshLayout) findViewById(R.id.swipeRefreshLayout); layout.setOnRefreshListener(new PullRefreshLayout.OnRefreshListener() { @Override - public void onRefresh() { + public void onRefresh(int direction) { layout.postDelayed(new Runnable() { @Override public void run() { @@ -43,6 +44,7 @@ public void run() { }, 4000); } }); + } static class ArrayAdapter extends RecyclerView.Adapter{ diff --git a/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/ScrollViewActivity.java b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/ScrollViewActivity.java index 7ecab6d..c1e7560 100644 --- a/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/ScrollViewActivity.java +++ b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/ScrollViewActivity.java @@ -20,13 +20,13 @@ protected void onCreate(Bundle savedInstanceState) { layout = (PullRefreshLayout) findViewById(R.id.swipeRefreshLayout); layout.setOnRefreshListener(new PullRefreshLayout.OnRefreshListener() { @Override - public void onRefresh() { + public void onRefresh(int direction) { layout.postDelayed(new Runnable() { @Override public void run() { layout.setRefreshing(false); } - }, 3000); + }, 10000); } }); layout.setColorSchemeColors(Color.GRAY); diff --git a/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/GankActivity.java b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/GankActivity.java new file mode 100644 index 0000000..f6c795b --- /dev/null +++ b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/GankActivity.java @@ -0,0 +1,97 @@ +package com.baoyz.pullrefreshlayout.sample.gank; + +import android.app.Activity; +import android.os.Bundle; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.widget.Toast; + +import com.baoyz.pullrefreshlayout.sample.R; +import com.baoyz.pullrefreshlayout.sample.gank.adapter.GankAdapter; +import com.baoyz.pullrefreshlayout.sample.gank.model.GankData; +import com.baoyz.pullrefreshlayout.sample.gank.network.GankApi; +import com.baoyz.widget.PullRefreshLayout; + +import retrofit.Call; +import retrofit.Callback; +import retrofit.MoshiConverterFactory; +import retrofit.Response; +import retrofit.Retrofit; + +/** + * Content from http://gank.io + */ +public class GankActivity extends Activity { + + private RecyclerView mRecyclerView; + private GankApi mGankApi; + private PullRefreshLayout mRefreshLayout; + private int mCurrentPage = 1; + private GankAdapter mAdapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gank); + + mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView); + mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); + mAdapter = new GankAdapter(); + mRecyclerView.setAdapter(mAdapter); + + mRefreshLayout = (PullRefreshLayout) findViewById(R.id.refreshLayout); + mRefreshLayout.setRefreshStyle(PullRefreshLayout.STYLE_SMARTISAN); + mRefreshLayout.setOnRefreshListener(new PullRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh(int direction) { + switch (direction) { + case PullRefreshLayout.DIRECTION_UP: + loadData(1); + break; + case PullRefreshLayout.DIRECTION_DOWN: + loadData(mCurrentPage + 1); + break; + } + } + }); + + mGankApi = new Retrofit + .Builder() + .baseUrl(GankApi.BASE_URL) + .addConverterFactory(MoshiConverterFactory.create()) + .build() + .create(GankApi.class); + + mRefreshLayout.setRefreshing(true); + loadData(mCurrentPage); + } + + private void loadData(final int page) { + Call call = mGankApi.getData(page); + call.enqueue(new Callback() { + @Override + public void onResponse(Response response, Retrofit retrofit) { + mRefreshLayout.setRefreshing(false); + if (!response.isSuccess()) { + Toast.makeText(GankActivity.this, response.code() + ", " + response.message(), Toast.LENGTH_SHORT).show(); + return; + } + mCurrentPage = page; + if (mCurrentPage == 1) { + mAdapter.clear(); + } + GankData data = response.body(); + if (data == null || data.getResults() == null || data.getResults().size() <= 0) { + return; + } + mAdapter.addItems(data.getResults()); + mAdapter.notifyDataSetChanged(); + } + + @Override + public void onFailure(Throwable throwable) { + mRefreshLayout.setRefreshing(false); + } + }); + } +} diff --git a/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/adapter/GankAdapter.java b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/adapter/GankAdapter.java new file mode 100644 index 0000000..23ad29f --- /dev/null +++ b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/adapter/GankAdapter.java @@ -0,0 +1,103 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 baoyongzhang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.baoyz.pullrefreshlayout.sample.gank.adapter; + +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.baoyz.pullrefreshlayout.sample.R; +import com.baoyz.pullrefreshlayout.sample.gank.model.GankItem; +import com.squareup.picasso.Picasso; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by baoyz on 15/1/14. + */ +public class GankAdapter extends RecyclerView.Adapter { + + private int mLastPosition = -1; + private final List mItems; + + public GankAdapter() { + mItems = new ArrayList<>(); + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { + return new ViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_feed, viewGroup, false)); + } + + public void addItems(List items) { + if (items == null || items.size() <= 0) + return; + mItems.addAll(items); + } + + public void clear() { + mItems.clear(); + } + + @Override + public void onBindViewHolder(GankAdapter.ViewHolder holder, int position) { + if (position > mLastPosition) { + mLastPosition = position; + startItemAnimation(holder, position); + } + GankItem item = mItems.get(position); + Picasso.with(holder.mView.getContext()).load(item.getUrl()).into(holder.mImageView); + } + + @Override + public int getItemCount() { + return mItems.size(); + } + + protected void startItemAnimation(final GankAdapter.ViewHolder holder, int position) { + holder.mView.post(new Runnable() { + @Override + public void run() { + holder.mView.setTranslationY(holder.mView.getMeasuredHeight() / 2); + holder.mView.setAlpha(0); + holder.mView.animate().translationY(0).alpha(1).setDuration(500).start(); + } + }); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + + public View mView; + public ImageView mImageView; + + public ViewHolder(View itemView) { + super(itemView); + mView = itemView; + mImageView = (ImageView) itemView.findViewById(R.id.imageView); + } + } +} diff --git a/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/model/GankData.java b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/model/GankData.java new file mode 100644 index 0000000..e37c43a --- /dev/null +++ b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/model/GankData.java @@ -0,0 +1,52 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 baoyongzhang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.baoyz.pullrefreshlayout.sample.gank.model; + +import java.util.List; + +/** + * android-PullRefreshLayout + * Created by baoyz on 15/10/18. + */ +public class GankData { + + private boolean error; + private List results; + + public boolean isError() { + return error; + } + + public void setError(boolean error) { + this.error = error; + } + + public List getResults() { + return results; + } + + public void setResults(List results) { + this.results = results; + } +} diff --git a/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/model/GankItem.java b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/model/GankItem.java new file mode 100644 index 0000000..e2df6b9 --- /dev/null +++ b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/model/GankItem.java @@ -0,0 +1,50 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 baoyongzhang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.baoyz.pullrefreshlayout.sample.gank.model; + +/** + * android-PullRefreshLayout + * Created by baoyz on 15/10/18. + */ +public class GankItem { + + private String url; + private String desc; + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/network/GankApi.java b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/network/GankApi.java new file mode 100644 index 0000000..6dd6f82 --- /dev/null +++ b/sample/src/main/java/com/baoyz/pullrefreshlayout/sample/gank/network/GankApi.java @@ -0,0 +1,42 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 baoyongzhang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.baoyz.pullrefreshlayout.sample.gank.network; + +import com.baoyz.pullrefreshlayout.sample.gank.model.GankData; + +import retrofit.Call; +import retrofit.http.GET; +import retrofit.http.Path; + +/** + * android-PullRefreshLayout + * Created by baoyz on 15/10/18. + */ +public interface GankApi { + + String BASE_URL = "http://gank.avosapps.com"; + + @GET("/api/data/福利/10/{page}") + Call getData(@Path("page")int page); +} diff --git a/sample/src/main/res/layout/activity_demo.xml b/sample/src/main/res/layout/activity_demo.xml index 78c03f3..7ca438b 100644 --- a/sample/src/main/res/layout/activity_demo.xml +++ b/sample/src/main/res/layout/activity_demo.xml @@ -24,4 +24,10 @@ android:onClick="onScrollViewClick" android:text="ScrollView"/> +