diff options
author | Roman Nurik <roman@nurik.net> | 2014-10-22 00:04:13 -0400 |
---|---|---|
committer | Roman Nurik <roman@nurik.net> | 2014-10-22 00:04:13 -0400 |
commit | f2e87424ea7cc0c3f8022f984966091ea746a23e (patch) | |
tree | e3fc3eb874cf7324a2974166243ce083be07b30b | |
parent | c6d00178d4d0b6d8378c6644c4e9d212acf3d0e3 (diff) | |
parent | 1d8ff282225275a06977489ed12d93ac925bca8e (diff) | |
download | iosched-f2e87424ea7cc0c3f8022f984966091ea746a23e.tar.gz |
Merge pull request #71 from romannurik/master
Update to v21 SwipeRefreshLayout. Also fix nav drawer BACK button bug.
6 files changed, 30 insertions, 874 deletions
diff --git a/android/src/main/java/com/google/samples/apps/iosched/ui/BaseActivity.java b/android/src/main/java/com/google/samples/apps/iosched/ui/BaseActivity.java index ea4f2b8..0d9c6cd 100644 --- a/android/src/main/java/com/google/samples/apps/iosched/ui/BaseActivity.java +++ b/android/src/main/java/com/google/samples/apps/iosched/ui/BaseActivity.java @@ -45,6 +45,7 @@ import android.preference.PreferenceManager; import android.provider.Settings; import android.support.v4.view.ViewCompat; import android.support.v4.widget.DrawerLayout; +import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.Toolbar; @@ -76,7 +77,6 @@ import com.google.samples.apps.iosched.sync.SyncHelper; import com.google.samples.apps.iosched.ui.debug.DebugActionRunnerActivity; import com.google.samples.apps.iosched.ui.widget.MultiSwipeRefreshLayout; import com.google.samples.apps.iosched.ui.widget.ScrimInsetsScrollView; -import com.google.samples.apps.iosched.ui.widget.SwipeRefreshLayout; import com.google.samples.apps.iosched.util.AccountUtils; import com.google.samples.apps.iosched.util.AnalyticsManager; import com.google.samples.apps.iosched.util.HelpUtils; @@ -270,11 +270,10 @@ public abstract class BaseActivity extends ActionBarActivity implements private void trySetupSwipeRefresh() { mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout); if (mSwipeRefreshLayout != null) { - mSwipeRefreshLayout.setColorScheme( + mSwipeRefreshLayout.setColorSchemeResources( R.color.refresh_progress_1, R.color.refresh_progress_2, - R.color.refresh_progress_3, - R.color.refresh_progress_4); + R.color.refresh_progress_3); mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { @@ -299,11 +298,13 @@ public abstract class BaseActivity extends ActionBarActivity implements return; } - if (mActionBarShown) { - mSwipeRefreshLayout.setProgressBarTop(mProgressBarTopWhenActionBarShown); - } else { - mSwipeRefreshLayout.setProgressBarTop(0); - } + int progressBarStartMargin = getResources().getDimensionPixelSize( + R.dimen.swipe_refresh_progress_bar_start_margin); + int progressBarEndMargin = getResources().getDimensionPixelSize( + R.dimen.swipe_refresh_progress_bar_end_margin); + int top = mActionBarShown ? mProgressBarTopWhenActionBarShown : 0; + mSwipeRefreshLayout.setProgressViewOffset(false, + top + progressBarStartMargin, top + progressBarEndMargin); } /** @@ -435,6 +436,12 @@ public abstract class BaseActivity extends ActionBarActivity implements return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(Gravity.START); } + protected void closeNavDrawer() { + if (mDrawerLayout != null) { + mDrawerLayout.closeDrawer(Gravity.START); + } + } + /** Populates the navigation drawer with the appropriate items. */ private void populateNavDrawer() { boolean attendeeAtVenue = PrefUtils.isAttendeeAtVenue(this); @@ -479,6 +486,15 @@ public abstract class BaseActivity extends ActionBarActivity implements createNavDrawerItems(); } + @Override + public void onBackPressed() { + if (isNavDrawerOpen()) { + closeNavDrawer(); + } else { + super.onBackPressed(); + } + } + private void createNavDrawerItems() { mDrawerItemsListContainer = (ViewGroup) findViewById(R.id.navdrawer_items_list); if (mDrawerItemsListContainer == null) { diff --git a/android/src/main/java/com/google/samples/apps/iosched/ui/widget/MultiSwipeRefreshLayout.java b/android/src/main/java/com/google/samples/apps/iosched/ui/widget/MultiSwipeRefreshLayout.java index 041e1f1..5c82736 100644 --- a/android/src/main/java/com/google/samples/apps/iosched/ui/widget/MultiSwipeRefreshLayout.java +++ b/android/src/main/java/com/google/samples/apps/iosched/ui/widget/MultiSwipeRefreshLayout.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.drawable.Drawable; +import android.support.v4.widget.SwipeRefreshLayout; import android.util.AttributeSet; import com.google.samples.apps.iosched.R; diff --git a/android/src/main/java/com/google/samples/apps/iosched/ui/widget/SwipeProgressBar.java b/android/src/main/java/com/google/samples/apps/iosched/ui/widget/SwipeProgressBar.java deleted file mode 100644 index f12b14e..0000000 --- a/android/src/main/java/com/google/samples/apps/iosched/ui/widget/SwipeProgressBar.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright 2014 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.samples.apps.iosched.ui.widget; - -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.RectF; -import android.support.v4.view.ViewCompat; -import android.view.View; -import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; - - -/** - * Custom progress bar that shows a cycle of colors as widening circles that - * overdraw each other. When finished, the bar is cleared from the inside out as - * the main cycle continues. Before running, this can also indicate how close - * the user is to triggering something (e.g. how far they need to pull down to - * trigger a refresh). - */ -final class SwipeProgressBar { - - // Default progress animation colors are grays. - private final static int COLOR1 = 0xB3000000; - private final static int COLOR2 = 0x80000000; - private final static int COLOR3 = 0x4d000000; - private final static int COLOR4 = 0x1a000000; - - // The duration of the animation cycle. - private static final int ANIMATION_DURATION_MS = 2000; - - // The duration of the animation to clear the bar. - private static final int FINISH_ANIMATION_DURATION_MS = 1000; - - // Interpolator for varying the speed of the animation. - private static final Interpolator INTERPOLATOR = BakedBezierInterpolator.getInstance(); - - private final Paint mPaint = new Paint(); - private final RectF mClipRect = new RectF(); - private float mTriggerPercentage; - private long mStartTime; - private long mFinishTime; - private boolean mRunning; - - // Colors used when rendering the animation, - private int mColor1; - private int mColor2; - private int mColor3; - private int mColor4; - private View mParent; - - private Rect mBounds = new Rect(); - - public SwipeProgressBar(View parent) { - mParent = parent; - mColor1 = COLOR1; - mColor2 = COLOR2; - mColor3 = COLOR3; - mColor4 = COLOR4; - } - - /** - * Set the four colors used in the progress animation. The first color will - * also be the color of the bar that grows in response to a user swipe - * gesture. - * - * @param color1 Integer representation of a color. - * @param color2 Integer representation of a color. - * @param color3 Integer representation of a color. - * @param color4 Integer representation of a color. - */ - void setColorScheme(int color1, int color2, int color3, int color4) { - mColor1 = color1; - mColor2 = color2; - mColor3 = color3; - mColor4 = color4; - } - - /** - * Update the progress the user has made toward triggering the swipe - * gesture. and use this value to update the percentage of the trigger that - * is shown. - */ - void setTriggerPercentage(float triggerPercentage) { - mTriggerPercentage = triggerPercentage; - mStartTime = 0; - ViewCompat.postInvalidateOnAnimation(mParent); - } - - /** - * Start showing the progress animation. - */ - void start() { - if (!mRunning) { - mTriggerPercentage = 0; - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mRunning = true; - mParent.postInvalidate(); - } - } - - /** - * Stop showing the progress animation. - */ - void stop() { - if (mRunning) { - mTriggerPercentage = 0; - mFinishTime = AnimationUtils.currentAnimationTimeMillis(); - mRunning = false; - mParent.postInvalidate(); - } - } - - /** - * @return Return whether the progress animation is currently running. - */ - boolean isRunning() { - return mRunning || mFinishTime > 0; - } - - void draw(Canvas canvas) { - final int width = mBounds.width(); - final int cx = width / 2; - final int cy = mBounds.top + mBounds.height() / 2; - boolean drawTriggerWhileFinishing = false; - int restoreCount = canvas.save(); - canvas.clipRect(mBounds); - if (mRunning || (mFinishTime > 0)) { - long now = AnimationUtils.currentAnimationTimeMillis(); - long elapsed = (now - mStartTime) % ANIMATION_DURATION_MS; - long iterations = (now - mStartTime) / ANIMATION_DURATION_MS; - float rawProgress = (elapsed / (ANIMATION_DURATION_MS / 100f)); - // If we're not running anymore, that means we're running through - // the finish animation. - if (!mRunning) { - // If the finish animation is done, don't draw anything, and - // don't repost. - if ((now - mFinishTime) >= FINISH_ANIMATION_DURATION_MS) { - mFinishTime = 0; - return; - } - // Otherwise, use a 0 opacity alpha layer to clear the animation - // from the inside out. This layer will prevent the circles from - // drawing within its bounds. - long finishElapsed = (now - mFinishTime) % FINISH_ANIMATION_DURATION_MS; - float finishProgress = (finishElapsed / (FINISH_ANIMATION_DURATION_MS / 100f)); - float pct = (finishProgress / 100f); - // Radius of the circle is half of the screen. - float clearRadius = width / 2 * INTERPOLATOR.getInterpolation(pct); - mClipRect.set(cx - clearRadius, mBounds.top, cx + clearRadius, mBounds.bottom); - canvas.saveLayerAlpha(mClipRect, 0, 0); - // Only draw the trigger if there is a space in the center of - // this refreshing view that needs to be filled in by the - // trigger. If the progress view is just still animating, let it - // continue animating. - drawTriggerWhileFinishing = true; - } - // First fill in with the last color that would have finished drawing. - if (iterations == 0) { - canvas.drawColor(mColor1); - } else { - if (rawProgress >= 0 && rawProgress < 25) { - canvas.drawColor(mColor4); - } else if (rawProgress >= 25 && rawProgress < 50) { - canvas.drawColor(mColor1); - } else if (rawProgress >= 50 && rawProgress < 75) { - canvas.drawColor(mColor2); - } else { - canvas.drawColor(mColor3); - } - } - // Then draw up to 4 overlapping concentric circles of varying radii, based on how far - // along we are in the cycle. - // progress 0-50 draw mColor2 - // progress 25-75 draw mColor3 - // progress 50-100 draw mColor4 - // progress 75 (wrap to 25) draw mColor1 - if ((rawProgress >= 0 && rawProgress <= 25)) { - float pct = (((rawProgress + 25) * 2) / 100f); - drawCircle(canvas, cx, cy, mColor1, pct); - } - if (rawProgress >= 0 && rawProgress <= 50) { - float pct = ((rawProgress * 2) / 100f); - drawCircle(canvas, cx, cy, mColor2, pct); - } - if (rawProgress >= 25 && rawProgress <= 75) { - float pct = (((rawProgress - 25) * 2) / 100f); - drawCircle(canvas, cx, cy, mColor3, pct); - } - if (rawProgress >= 50 && rawProgress <= 100) { - float pct = (((rawProgress - 50) * 2) / 100f); - drawCircle(canvas, cx, cy, mColor4, pct); - } - if ((rawProgress >= 75 && rawProgress <= 100)) { - float pct = (((rawProgress - 75) * 2) / 100f); - drawCircle(canvas, cx, cy, mColor1, pct); - } - if (mTriggerPercentage > 0 && drawTriggerWhileFinishing) { - // There is some portion of trigger to draw. Restore the canvas, - // then draw the trigger. Otherwise, the trigger does not appear - // until after the bar has finished animating and appears to - // just jump in at a larger width than expected. - canvas.restoreToCount(restoreCount); - restoreCount = canvas.save(); - canvas.clipRect(mBounds); - drawTrigger(canvas, cx, cy); - } - // Keep running until we finish out the last cycle. - ViewCompat.postInvalidateOnAnimation(mParent); - } else { - // Otherwise if we're in the middle of a trigger, draw that. - if (mTriggerPercentage > 0 && mTriggerPercentage <= 1.0) { - drawTrigger(canvas, cx, cy); - } - } - canvas.restoreToCount(restoreCount); - } - - private void drawTrigger(Canvas canvas, int cx, int cy) { - mPaint.setColor(mColor1); - canvas.drawCircle(cx, cy, cx * mTriggerPercentage, mPaint); - } - - /** - * Draws a circle centered in the view. - * - * @param canvas the canvas to draw on - * @param cx the center x coordinate - * @param cy the center y coordinate - * @param color the color to draw - * @param pct the percentage of the view that the circle should cover - */ - private void drawCircle(Canvas canvas, float cx, float cy, int color, float pct) { - mPaint.setColor(color); - canvas.save(); - canvas.translate(cx, cy); - float radiusScale = INTERPOLATOR.getInterpolation(pct); - canvas.scale(radiusScale, radiusScale); - canvas.drawCircle(0, 0, cx, mPaint); - canvas.restore(); - } - - /** - * Set the drawing bounds of this SwipeProgressBar. - */ - void setBounds(int left, int top, int right, int bottom) { - mBounds.left = left; - mBounds.top = top; - mBounds.right = right; - mBounds.bottom = bottom; - } -} diff --git a/android/src/main/java/com/google/samples/apps/iosched/ui/widget/SwipeRefreshLayout.java b/android/src/main/java/com/google/samples/apps/iosched/ui/widget/SwipeRefreshLayout.java deleted file mode 100755 index 903212a..0000000 --- a/android/src/main/java/com/google/samples/apps/iosched/ui/widget/SwipeRefreshLayout.java +++ /dev/null @@ -1,596 +0,0 @@ -/* - * Copyright 2014 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.samples.apps.iosched.ui.widget; - -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.support.v4.view.MotionEventCompat; -import android.support.v4.view.ViewCompat; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.Animation; -import android.view.animation.Animation.AnimationListener; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Transformation; -import android.widget.AbsListView; - - -/** - * The SwipeRefreshLayout should be used whenever the user can refresh the - * contents of a view via a vertical swipe gesture. The activity that - * instantiates this view should add an OnRefreshListener to be notified - * whenever the swipe to refresh gesture is completed. The SwipeRefreshLayout - * will notify the listener each and every time the gesture is completed again; - * the listener is responsible for correctly determining when to actually - * initiate a refresh of its content. If the listener determines there should - * not be a refresh, it must call setRefreshing(false) to cancel any visual - * indication of a refresh. If an activity wishes to show just the progress - * animation, it should call setRefreshing(true). To disable the gesture and progress - * animation, call setEnabled(false) on the view. - * - * <p> This layout should be made the parent of the view that will be refreshed as a - * result of the gesture and can only support one direct child. This view will - * also be made the target of the gesture and will be forced to match both the - * width and the height supplied in this layout. The SwipeRefreshLayout does not - * provide accessibility events; instead, a menu item must be provided to allow - * refresh of the content wherever this gesture is used.</p> - */ -public class SwipeRefreshLayout extends ViewGroup { - private static final String LOG_TAG = SwipeRefreshLayout.class.getSimpleName(); - - private static final long RETURN_TO_ORIGINAL_POSITION_TIMEOUT = 300; - private static final float ACCELERATE_INTERPOLATION_FACTOR = 1.5f; - private static final float DECELERATE_INTERPOLATION_FACTOR = 2f; - private static final float PROGRESS_BAR_HEIGHT = 4; - private static final float MAX_SWIPE_DISTANCE_FACTOR = .6f; - private static final int REFRESH_TRIGGER_DISTANCE = 120; - private static final int INVALID_POINTER = -1; - - private SwipeProgressBar mProgressBar; //the thing that shows progress is going - private View mTarget; //the content that gets pulled down - private int mOriginalOffsetTop; - private OnRefreshListener mListener; - private int mFrom; - private boolean mRefreshing = false; - private int mTouchSlop; - private float mDistanceToTriggerSync = -1; - private int mMediumAnimationDuration; - private float mFromPercentage = 0; - private float mCurrPercentage = 0; - private int mProgressBarHeight; - private int mCurrentTargetOffsetTop; - private int mProgressBarTop; - - private float mInitialMotionY; - private float mLastMotionY; - private boolean mIsBeingDragged; - private int mActivePointerId = INVALID_POINTER; - - // Target is returning to its start offset because it was cancelled or a - // refresh was triggered. - private boolean mReturningToStart; - private final DecelerateInterpolator mDecelerateInterpolator; - private final AccelerateInterpolator mAccelerateInterpolator; - private static final int[] LAYOUT_ATTRS = new int[] { - android.R.attr.enabled - }; - - private final Animation mAnimateToStartPosition = new Animation() { - @Override - public void applyTransformation(float interpolatedTime, Transformation t) { - int targetTop = 0; - if (mFrom != mOriginalOffsetTop) { - targetTop = (mFrom + (int)((mOriginalOffsetTop - mFrom) * interpolatedTime)); - } - int offset = targetTop - mTarget.getTop(); - final int currentTop = mTarget.getTop(); - if (offset + currentTop < 0) { - offset = 0 - currentTop; - } - setTargetOffsetTopAndBottom(offset); - } - }; - - private Animation mShrinkTrigger = new Animation() { - @Override - public void applyTransformation(float interpolatedTime, Transformation t) { - float percent = mFromPercentage + ((0 - mFromPercentage) * interpolatedTime); - mProgressBar.setTriggerPercentage(percent); - } - }; - - private final AnimationListener mReturnToStartPositionListener = new BaseAnimationListener() { - @Override - public void onAnimationEnd(Animation animation) { - // Once the target content has returned to its start position, reset - // the target offset to 0 - mCurrentTargetOffsetTop = 0; - } - }; - - private final AnimationListener mShrinkAnimationListener = new BaseAnimationListener() { - @Override - public void onAnimationEnd(Animation animation) { - mCurrPercentage = 0; - } - }; - - private final Runnable mReturnToStartPosition = new Runnable() { - - @Override - public void run() { - mReturningToStart = true; - animateOffsetToStartPosition(mCurrentTargetOffsetTop + getPaddingTop(), - mReturnToStartPositionListener); - } - - }; - - // Cancel the refresh gesture and animate everything back to its original state. - private final Runnable mCancel = new Runnable() { - - @Override - public void run() { - mReturningToStart = true; - // Timeout fired since the user last moved their finger; animate the - // trigger to 0 and put the target back at its original position - if (mProgressBar != null) { - mFromPercentage = mCurrPercentage; - mShrinkTrigger.setDuration(mMediumAnimationDuration); - mShrinkTrigger.setAnimationListener(mShrinkAnimationListener); - mShrinkTrigger.reset(); - mShrinkTrigger.setInterpolator(mDecelerateInterpolator); - startAnimation(mShrinkTrigger); - } - animateOffsetToStartPosition(mCurrentTargetOffsetTop + getPaddingTop(), - mReturnToStartPositionListener); - } - - }; - - /** - * Simple constructor to use when creating a SwipeRefreshLayout from code. - * @param context - */ - public SwipeRefreshLayout(Context context) { - this(context, null); - } - - /** - * Constructor that is called when inflating SwipeRefreshLayout from XML. - * @param context - * @param attrs - */ - public SwipeRefreshLayout(Context context, AttributeSet attrs) { - super(context, attrs); - - mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); - - mMediumAnimationDuration = getResources().getInteger( - android.R.integer.config_mediumAnimTime); - - setWillNotDraw(false); - mProgressBar = new SwipeProgressBar(this); - final DisplayMetrics metrics = getResources().getDisplayMetrics(); - mProgressBarHeight = (int) (metrics.density * PROGRESS_BAR_HEIGHT); - mDecelerateInterpolator = new DecelerateInterpolator(DECELERATE_INTERPOLATION_FACTOR); - mAccelerateInterpolator = new AccelerateInterpolator(ACCELERATE_INTERPOLATION_FACTOR); - - final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); - setEnabled(a.getBoolean(0, true)); - a.recycle(); - } - - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - removeCallbacks(mCancel); - removeCallbacks(mReturnToStartPosition); - } - - @Override - public void onDetachedFromWindow() { - super.onDetachedFromWindow(); - removeCallbacks(mReturnToStartPosition); - removeCallbacks(mCancel); - } - - private void animateOffsetToStartPosition(int from, AnimationListener listener) { - mFrom = from; - mAnimateToStartPosition.reset(); - mAnimateToStartPosition.setDuration(mMediumAnimationDuration); - mAnimateToStartPosition.setAnimationListener(listener); - mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator); - mTarget.startAnimation(mAnimateToStartPosition); - } - - /** - * Set the listener to be notified when a refresh is triggered via the swipe - * gesture. - */ - public void setOnRefreshListener(OnRefreshListener listener) { - mListener = listener; - } - - private void setTriggerPercentage(float percent) { - if (percent == 0f) { - // No-op. A null trigger means it's uninitialized, and setting it to zero-percent - // means we're trying to reset state, so there's nothing to reset in this case. - mCurrPercentage = 0; - return; - } - mCurrPercentage = percent; - mProgressBar.setTriggerPercentage(percent); - } - - /** - * Notify the widget that refresh state has changed. Do not call this when - * refresh is triggered by a swipe gesture. - * - * @param refreshing Whether or not the view should show refresh progress. - */ - public void setRefreshing(boolean refreshing) { - if (mRefreshing != refreshing) { - ensureTarget(); - mCurrPercentage = 0; - mRefreshing = refreshing; - if (mRefreshing) { - mProgressBar.start(); - } else { - mProgressBar.stop(); - } - } - } - - /** - * @deprecated Use {@link #setColorSchemeResources(int, int, int, int)} - */ - @Deprecated - public void setColorScheme(int colorRes1, int colorRes2, int colorRes3, int colorRes4) { - setColorSchemeResources(colorRes1, colorRes2, colorRes3, colorRes4); - } - - /** - * Set the four colors used in the progress animation from color resources. - * The first color will also be the color of the bar that grows in response - * to a user swipe gesture. - */ - public void setColorSchemeResources(int colorRes1, int colorRes2, int colorRes3, - int colorRes4) { - final Resources res = getResources(); - setColorSchemeColors(res.getColor(colorRes1), res.getColor(colorRes2), - res.getColor(colorRes3), res.getColor(colorRes4)); - } - - /** - * Set the four colors used in the progress animation. The first color will - * also be the color of the bar that grows in response to a user swipe - * gesture. - */ - public void setColorSchemeColors(int color1, int color2, int color3, int color4) { - ensureTarget(); - mProgressBar.setColorScheme(color1, color2, color3, color4); - } - - /** - * @return Whether the SwipeRefreshWidget is actively showing refresh - * progress. - */ - public boolean isRefreshing() { - return mRefreshing; - } - - private void ensureTarget() { - // Don't bother getting the parent height if the parent hasn't been laid out yet. - if (mTarget == null) { - if (getChildCount() > 1 && !isInEditMode()) { - throw new IllegalStateException( - "SwipeRefreshLayout can host only one direct child"); - } - mTarget = getChildAt(0); - mOriginalOffsetTop = mTarget.getTop() + getPaddingTop(); - } - if (mDistanceToTriggerSync == -1) { - if (getParent() != null && ((View)getParent()).getHeight() > 0) { - final DisplayMetrics metrics = getResources().getDisplayMetrics(); - mDistanceToTriggerSync = (int) Math.min( - ((View) getParent()) .getHeight() * MAX_SWIPE_DISTANCE_FACTOR, - REFRESH_TRIGGER_DISTANCE * metrics.density); - } - } - } - - @Override - public void draw(Canvas canvas) { - super.draw(canvas); - mProgressBar.draw(canvas); - } - - public void setProgressBarTop(int top) { - mProgressBarTop = top; - mProgressBar.setBounds(0, mProgressBarTop, getWidth(), mProgressBarTop + mProgressBarHeight); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - final int width = getMeasuredWidth(); - final int height = getMeasuredHeight(); - mProgressBar.setBounds(0, mProgressBarTop, getWidth(), mProgressBarTop + mProgressBarHeight); - if (getChildCount() == 0) { - return; - } - final View child = getChildAt(0); - final int childLeft = getPaddingLeft(); - final int childTop = mCurrentTargetOffsetTop + getPaddingTop(); - final int childWidth = width - getPaddingLeft() - getPaddingRight(); - final int childHeight = height - getPaddingTop() - getPaddingBottom(); - child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); - } - - @Override - public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - if (getChildCount() > 1 && !isInEditMode()) { - throw new IllegalStateException("SwipeRefreshLayout can host only one direct child"); - } - if (getChildCount() > 0) { - getChildAt(0).measure( - MeasureSpec.makeMeasureSpec( - getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), - MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec( - getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), - MeasureSpec.EXACTLY)); - } - } - - /** - * @return Whether it is possible for the child view of this layout to - * scroll up. Override this if the child view is a custom view. - */ - public 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 - public boolean onInterceptTouchEvent(MotionEvent ev) { - ensureTarget(); - - final int action = MotionEventCompat.getActionMasked(ev); - - if (mReturningToStart && action == MotionEvent.ACTION_DOWN) { - mReturningToStart = false; - } - - if (!isEnabled() || mReturningToStart || canChildScrollUp()) { - // Fail fast if we're not in a state where a swipe is possible - return false; - } - - switch (action) { - case MotionEvent.ACTION_DOWN: - mLastMotionY = mInitialMotionY = ev.getY(); - mActivePointerId = MotionEventCompat.getPointerId(ev, 0); - mIsBeingDragged = false; - mCurrPercentage = 0; - break; - - case MotionEvent.ACTION_MOVE: - if (mActivePointerId == INVALID_POINTER) { - Log.e(LOG_TAG, "Got ACTION_MOVE event but don't have an active pointer id."); - return false; - } - - final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); - if (pointerIndex < 0) { - Log.e(LOG_TAG, "Got ACTION_MOVE event but have an invalid active pointer id."); - return false; - } - - final float y = MotionEventCompat.getY(ev, pointerIndex); - final float yDiff = y - mInitialMotionY; - if (yDiff > mTouchSlop) { - mLastMotionY = y; - mIsBeingDragged = true; - } - break; - - case MotionEventCompat.ACTION_POINTER_UP: - onSecondaryPointerUp(ev); - break; - - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - mIsBeingDragged = false; - mCurrPercentage = 0; - mActivePointerId = INVALID_POINTER; - break; - } - - return mIsBeingDragged; - } - - @Override - public void requestDisallowInterceptTouchEvent(boolean b) { - // Nope. - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - final int action = MotionEventCompat.getActionMasked(ev); - - if (mReturningToStart && action == MotionEvent.ACTION_DOWN) { - mReturningToStart = false; - } - - if (!isEnabled() || mReturningToStart || canChildScrollUp()) { - // Fail fast if we're not in a state where a swipe is possible - return false; - } - - switch (action) { - case MotionEvent.ACTION_DOWN: - mLastMotionY = mInitialMotionY = ev.getY(); - mActivePointerId = MotionEventCompat.getPointerId(ev, 0); - mIsBeingDragged = false; - mCurrPercentage = 0; - break; - - case MotionEvent.ACTION_MOVE: - final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); - if (pointerIndex < 0) { - Log.e(LOG_TAG, "Got ACTION_MOVE event but have an invalid active pointer id."); - return false; - } - - final float y = MotionEventCompat.getY(ev, pointerIndex); - final float yDiff = y - mInitialMotionY; - - if (!mIsBeingDragged && yDiff > mTouchSlop) { - mIsBeingDragged = true; - } - - if (mIsBeingDragged) { - // User velocity passed min velocity; trigger a refresh - if (yDiff > mDistanceToTriggerSync) { - // User movement passed distance; trigger a refresh - startRefresh(); - } else { - // Just track the user's movement - setTriggerPercentage( - mAccelerateInterpolator.getInterpolation( - yDiff / mDistanceToTriggerSync)); - updateContentOffsetTop((int) (yDiff)); - if (mLastMotionY > y && mTarget.getTop() == getPaddingTop()) { - // If the user puts the view back at the top, we - // don't need to. This shouldn't be considered - // cancelling the gesture as the user can restart from the top. - removeCallbacks(mCancel); - } else { - updatePositionTimeout(); - } - } - mLastMotionY = y; - } - break; - - case MotionEventCompat.ACTION_POINTER_DOWN: { - final int index = MotionEventCompat.getActionIndex(ev); - mLastMotionY = MotionEventCompat.getY(ev, index); - mActivePointerId = MotionEventCompat.getPointerId(ev, index); - break; - } - - case MotionEventCompat.ACTION_POINTER_UP: - onSecondaryPointerUp(ev); - break; - - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - mIsBeingDragged = false; - mCurrPercentage = 0; - mActivePointerId = INVALID_POINTER; - return false; - } - - return true; - } - - private void startRefresh() { - removeCallbacks(mCancel); - mReturnToStartPosition.run(); - setRefreshing(true); - mListener.onRefresh(); - } - - private void updateContentOffsetTop(int targetTop) { - final int currentTop = mTarget.getTop(); - if (targetTop > mDistanceToTriggerSync) { - targetTop = (int) mDistanceToTriggerSync; - } else if (targetTop < 0) { - targetTop = 0; - } - setTargetOffsetTopAndBottom(targetTop - currentTop); - } - - private void setTargetOffsetTopAndBottom(int offset) { - mTarget.offsetTopAndBottom(offset); - mCurrentTargetOffsetTop = mTarget.getTop(); - } - - private void updatePositionTimeout() { - removeCallbacks(mCancel); - postDelayed(mCancel, RETURN_TO_ORIGINAL_POSITION_TIMEOUT); - } - - private void onSecondaryPointerUp(MotionEvent ev) { - final int pointerIndex = MotionEventCompat.getActionIndex(ev); - final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); - if (pointerId == mActivePointerId) { - // This was our active pointer going up. Choose a new - // active pointer and adjust accordingly. - final int newPointerIndex = pointerIndex == 0 ? 1 : 0; - mLastMotionY = MotionEventCompat.getY(ev, newPointerIndex); - mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); - } - } - - /** - * Classes that wish to be notified when the swipe gesture correctly - * triggers a refresh should implement this interface. - */ - public interface OnRefreshListener { - public void onRefresh(); - } - - /** - * Simple AnimationListener to avoid having to implement unneeded methods in - * AnimationListeners. - */ - private class BaseAnimationListener implements AnimationListener { - @Override - public void onAnimationStart(Animation animation) { - } - - @Override - public void onAnimationEnd(Animation animation) { - } - - @Override - public void onAnimationRepeat(Animation animation) { - } - } -} diff --git a/android/src/main/res/values/colors.xml b/android/src/main/res/values/colors.xml index cc9a095..d5d91a2 100644 --- a/android/src/main/res/values/colors.xml +++ b/android/src/main/res/values/colors.xml @@ -55,8 +55,7 @@ <color name="refresh_progress_1">@color/theme_accent_2</color> <color name="refresh_progress_2">@color/theme_accent_1</color> - <color name="refresh_progress_3">@color/theme_primary_dark</color> - <color name="refresh_progress_4">@color/theme_primary_light</color> + <color name="refresh_progress_3">@color/theme_primary</color> <color name="data_item_background_light">#ffffff</color> <color name="data_item_lightbg_title">#404040</color> diff --git a/android/src/main/res/values/dimens.xml b/android/src/main/res/values/dimens.xml index 91dd3c1..dafa969 100644 --- a/android/src/main/res/values/dimens.xml +++ b/android/src/main/res/values/dimens.xml @@ -79,6 +79,9 @@ <dimen name="action_bar_auto_hide_min_y">152dp</dimen> <dimen name="action_bar_auto_hide_sensivity">48dp</dimen> + <dimen name="swipe_refresh_progress_bar_start_margin">-40dp</dimen> + <dimen name="swipe_refresh_progress_bar_end_margin">16dp</dimen> + <dimen name="browse_sessions_anim_amount">400dp</dimen> <dimen name="butter_bar_height">64dp</dimen> <dimen name="filterbar_height">48dp</dimen> |