Android Open Source - FootyNews Actions Content View






From Project

Back to project page FootyNews.

License

The source code is released under:

MIT License

If you think the Android project FootyNews listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*******************************************************************************
 * Copyright 2012 Steven Rudenko//from  w  w  w.  j a v a 2  s  .  c o m
 * 
 * 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 shared.ui.actionscontentview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.LinearLayout;
import android.widget.Scroller;

public class ActionsContentView extends ViewGroup {
  private static final String TAG = ActionsContentView.class.getSimpleName();
  private static final boolean DEBUG = false;

  public interface OnActionsContentListener {
    public void onContentStateChanged(ActionsContentView v, boolean isContentShown);

    public void onContentStateInAction(ActionsContentView v, boolean isContentShowing);
  }

  private static final int FLING_MIN = 1000;

  /**
   * Spacing will be calculated as offset from right bound of view.
   */
  public static final int SPACING_RIGHT_OFFSET = 0;
  /**
   * Spacing will be calculated as right bound of actions bar container.
   */
  public static final int SPACING_ACTIONS_WIDTH = 1;

  /**
   * Fade is disabled.
   */
  public static final int FADE_NONE = 0;
  /**
   * Fade applies to actions container.
   */
  public static final int FADE_ACTIONS = 1;
  /**
   * Fade applies to content container.
   */
  public static final int FADE_CONTENT = 2;
  /**
   * Fade applies to every container.
   */
  public static final int FADE_BOTH = 3;

  /**
   * Swiping will be handled at any point of screen.
   */
  public static final int SWIPING_ALL = 0;
  /**
   * Swiping will be handled starting from screen edge only.
   */
  public static final int SWIPING_EDGE = 1;

  public static final int EFFECTS_NONE = 0;
  public static final int EFFECTS_SCROLL_OPENING = 1 << 0;
  public static final int EFFECTS_SCROLL_CLOSING = 1 << 1;
  public static final int EFFECTS_SCROLL = EFFECTS_SCROLL_OPENING | EFFECTS_SCROLL_CLOSING;
  public static final int EFFECTS_FLING_OPENING = 1 << 2;
  public static final int EFFECTS_FLING_CLOSING = 1 << 3;
  public static final int EFFECTS_FLING = EFFECTS_FLING_OPENING | EFFECTS_FLING_CLOSING;
  public static final int EFFECTS_ALL = EFFECTS_SCROLL | EFFECTS_FLING;

  private final ContentScrollController mScrollController;
  private final GestureDetector mGestureDetector;

  private final View viewShadow;
  private final ActionsLayout viewActionsContainer;
  private final ContentLayout viewContentContainer;

  /**
   * Spacing type.
   */
  private int mSpacingType = SPACING_RIGHT_OFFSET;
  /**
   * Value of spacing to use.
   */
  private int mSpacing;

  /**
   * Value of actions container spacing to use.
   */
  private int mActionsSpacing;

  /**
   * Value of shadow width.
   */
  private int mShadowWidth = 0;

  /**
   * Indicates how long flinging will take time in milliseconds.
   */
  private int mFlingDuration = 250;

  /**
   * Fade type.
   */
  private int mFadeType = FADE_NONE;
  /**
   * Max fade value.
   */
  private int mFadeValue;

  /**
   * Indicates whether swiping is enabled or not.
   */
  private boolean isSwipingEnabled = true;
  /**
   * Swiping type.
   */
  private int mSwipeType = FADE_NONE;
  /**
   * Swiping edge width.
   */
  private int mSwipeEdgeWidth;

  /**
   * Indicates whether refresh of content position should be done on next layout calculation.
   */
  private boolean mForceRefresh = false;

  private int mEffects = EFFECTS_ALL;

  private OnActionsContentListener mOnActionsContentListener;

  public ActionsContentView(Context context) {
    this(context, null);
  }

  public ActionsContentView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public ActionsContentView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    setClipChildren(false);
    setClipToPadding(false);

    // reading attributes
    final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ActionsContentView);
    mSpacingType = a.getInteger(R.styleable.ActionsContentView_spacing_type, SPACING_RIGHT_OFFSET);
    final int spacingDefault = context.getResources().getDimensionPixelSize(R.dimen.default_actionscontentview_spacing);
    mSpacing = a.getDimensionPixelSize(R.styleable.ActionsContentView_spacing, spacingDefault);
    final int actionsSpacingDefault = context.getResources().getDimensionPixelSize(R.dimen.default_actionscontentview_actions_spacing);
    mActionsSpacing = a.getDimensionPixelSize(R.styleable.ActionsContentView_actions_spacing, actionsSpacingDefault);

    final int actionsLayout = a.getResourceId(R.styleable.ActionsContentView_actions_layout, 0);
    final int contentLayout = a.getResourceId(R.styleable.ActionsContentView_content_layout, 0);

    mShadowWidth = a.getDimensionPixelSize(R.styleable.ActionsContentView_shadow_width, 0);
    final int shadowDrawableRes = a.getResourceId(R.styleable.ActionsContentView_shadow_drawable, 0);

    mFadeType = a.getInteger(R.styleable.ActionsContentView_fade_type, FADE_NONE);
    final int fadeValueDefault = context.getResources().getInteger(R.integer.default_actionscontentview_fade_max_value);
    mFadeValue = (int) a.getInt(R.styleable.ActionsContentView_fade_max_value, fadeValueDefault);

    setFadeValue(mFadeValue);

    final int flingDurationDefault = context.getResources().getInteger(R.integer.default_actionscontentview_fling_duration);
    mFlingDuration = a.getInteger(R.styleable.ActionsContentView_fling_duration, flingDurationDefault);

    mSwipeType = a.getInteger(R.styleable.ActionsContentView_swiping_type, SWIPING_EDGE);
    final int swipingEdgeWidthDefault = context.getResources().getDimensionPixelSize(R.dimen.default_actionscontentview_swiping_edge_width);
    mSwipeEdgeWidth = a.getDimensionPixelSize(R.styleable.ActionsContentView_swiping_edge_width, swipingEdgeWidthDefault);
    isSwipingEnabled = a.getBoolean(R.styleable.ActionsContentView_swiping_enabled, true);

    final int effectActionsRes = a.getResourceId(R.styleable.ActionsContentView_effect_actions, 0);
    final int effectContentRes = a.getResourceId(R.styleable.ActionsContentView_effect_content, 0);
    mEffects = a.getInt(R.styleable.ActionsContentView_effects, EFFECTS_ALL);

    final int effectsInterpolatorRes = a.getResourceId(R.styleable.ActionsContentView_effects_interpolator, 0);

    a.recycle();

    if (DEBUG) {
      Log.d(TAG, "Values from layout");
      Log.d(TAG, "  spacing type: " + mSpacingType);
      Log.d(TAG, "  spacing value: " + mSpacing);
      Log.d(TAG, "  actions spacing value: " + mActionsSpacing);
      Log.d(TAG, "  actions layout id: " + actionsLayout);
      Log.d(TAG, "  content layout id: " + contentLayout);
      Log.d(TAG, "  shadow drawable: " + shadowDrawableRes);
      Log.d(TAG, "  shadow width: " + mShadowWidth);
      Log.d(TAG, "  fade type: " + mFadeType);
      Log.d(TAG, "  fade max value: " + mFadeValue);
      Log.d(TAG, "  fling duration: " + mFlingDuration);
      Log.d(TAG, "  swiping type: " + mSwipeType);
      Log.d(TAG, "  swiping edge width: " + mSwipeEdgeWidth);
      Log.d(TAG, "  swiping enabled: " + isSwipingEnabled);
      Log.d(TAG, "  effects: " + mEffects);
      Log.d(TAG, "  effect actions: " + effectActionsRes);
      Log.d(TAG, "  effect content: " + effectContentRes);
      Log.d(TAG, "  effects interpolator: " + effectsInterpolatorRes);
    }

    final Scroller effectsScroller;
    if (effectsInterpolatorRes > 0) {
      final Interpolator interpolator = AnimationUtils.loadInterpolator(getContext(), effectsInterpolatorRes);
      effectsScroller = new Scroller(context, interpolator);
    } else {
      effectsScroller = new Scroller(context);
    }

    mScrollController = new ContentScrollController(new Scroller(context), effectsScroller);

    mGestureDetector = new GestureDetector(context, mScrollController);
    mGestureDetector.setIsLongpressEnabled(true);

    final LayoutInflater inflater = LayoutInflater.from(context);
    viewActionsContainer = new ActionsLayout(context);
    if (actionsLayout != 0)
      inflater.inflate(actionsLayout, viewActionsContainer, true);

    super.addView(viewActionsContainer, 0, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

    viewContentContainer = new ContentLayout(context);
    viewContentContainer.setOnSwipeListener(new ContentLayout.OnSwipeListener() {
      @Override
      public void onSwipe(int scrollPosition) {
        updateScrollFactor();
      }
    });

    viewShadow = new View(context);
    viewShadow.setBackgroundResource(shadowDrawableRes);
    final LinearLayout.LayoutParams shadowParams = new LinearLayout.LayoutParams(mShadowWidth, LinearLayout.LayoutParams.MATCH_PARENT);
    viewShadow.setLayoutParams(shadowParams);
    viewContentContainer.addView(viewShadow);

    if (mShadowWidth <= 0 || shadowDrawableRes == 0) {
      viewShadow.setVisibility(GONE);
    }

    if (contentLayout != 0)
      inflater.inflate(contentLayout, viewContentContainer, true);

    super.addView(viewContentContainer, 1, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

    if ( effectActionsRes > 0 ) {
      viewActionsContainer.getController().setEffects(effectActionsRes);
    }
    if ( effectContentRes > 0 ) {
      viewContentContainer.getController().setEffects(effectContentRes);
    }
  }

  public void setOnActionsContentListener(OnActionsContentListener listener) {
    mOnActionsContentListener = listener;
  }

  public OnActionsContentListener getOnActionsContentListener() {
    return mOnActionsContentListener;
  }

  /**
   * This method is not supported and throws an UnsupportedOperationException when called.
   *
   * @param child Ignored.
   *
   * @throws UnsupportedOperationException Every time this method is invoked.
   */
  @Override
  public void addView(View child) {
    throw new UnsupportedOperationException("addView(View) is not supported in " + TAG);
  }

  /**
   * This method is not supported and throws an UnsupportedOperationException when called.
   *
   * @param child Ignored.
   * @param index Ignored.
   *
   * @throws UnsupportedOperationException Every time this method is invoked.
   */
  @Override
  public void addView(View child, int index) {
    throw new UnsupportedOperationException("addView(View, int) is not supported in " + TAG);
  }

  /**
   * This method is not supported and throws an UnsupportedOperationException when called.
   *
   * @param child Ignored.
   * @param params Ignored.
   *
   * @throws UnsupportedOperationException Every time this method is invoked.
   */
  @Override
  public void addView(View child, LayoutParams params) {
    throw new UnsupportedOperationException("addView(View, LayoutParams) is not supported in " + TAG);
  }

  /**
   * This method is not supported and throws an UnsupportedOperationException when called.
   *
   * @param child Ignored.
   * @param index Ignored.
   * @param params Ignored.
   *
   * @throws UnsupportedOperationException Every time this method is invoked.
   */
  @Override
  public void addView(View child, int index, LayoutParams params) {
    throw new UnsupportedOperationException("addView(View, int, LayoutParams) is not supported in " + TAG);
  }

  /**
   * This method is not supported and throws an UnsupportedOperationException when called.
   *
   * @param child Ignored.
   *
   * @throws UnsupportedOperationException Every time this method is invoked.
   */
  @Override
  public void removeView(View child) {
    throw new UnsupportedOperationException("removeView(View) is not supported in " + TAG);
  }

  /**
   * This method is not supported and throws an UnsupportedOperationException when called.
   *
   * @param index Ignored.
   *
   * @throws UnsupportedOperationException Every time this method is invoked.
   */
  @Override
  public void removeViewAt(int index) {
    throw new UnsupportedOperationException("removeViewAt(int) is not supported in " + TAG);
  }

  /**
   * This method is not supported and throws an UnsupportedOperationException when called.
   *
   * @throws UnsupportedOperationException Every time this method is invoked.
   */
  @Override
  public void removeAllViews() {
    throw new UnsupportedOperationException("removeAllViews() is not supported in " + TAG);
  }

  public Parcelable onSaveInstanceState() {
    final Parcelable superState = super.onSaveInstanceState();
    final SavedState ss = new SavedState(superState);
    ss.isContentShown = isContentShown();
    ss.mSpacingType = getSpacingType();
    ss.mSpacing = getSpacingWidth();
    ss.mActionsSpacing = getActionsSpacingWidth();
    ss.isShadowVisible  = isShadowVisible();
    ss.mShadowWidth = getShadowWidth();
    ss.isSwipingEnabled = isSwipingEnabled();
    ss.mFlingDuration = getFlingDuration();
    ss.mFadeType = getFadeType();
    ss.mFadeValue = getFadeValue();
    ss.mSwipeType = getSwipingType();
    ss.mSwipeEdgeWidth = getSwipingEdgeWidth();
    return ss;
  }

  public void onRestoreInstanceState(Parcelable state) {
    if (!(state instanceof SavedState)) {
      super.onRestoreInstanceState(state);
      return;
    }

    final SavedState ss = (SavedState)state;
    super.onRestoreInstanceState(ss.getSuperState());

    mScrollController.isContentShown = ss.isContentShown;

    mSpacingType = ss.mSpacingType;
    mSpacing = ss.mSpacing;
    mActionsSpacing = ss.mActionsSpacing;
    isSwipingEnabled = ss.isSwipingEnabled;
    mSwipeType = ss.mSwipeType;
    mSwipeEdgeWidth = ss.mSwipeEdgeWidth;
    mFlingDuration = ss.mFlingDuration;
    mFadeType = ss.mFadeType;
    mFadeValue = ss.mFadeValue;

    viewShadow.setVisibility(ss.isShadowVisible ? VISIBLE : GONE);

    // this will call requestLayout() to calculate layout according to values
    setShadowWidth(ss.mShadowWidth);
  }

  public ViewGroup getActionsContainer() {
    return viewActionsContainer;
  }

  public ViewGroup getContentContainer() {
    return viewContentContainer;
  }

  public ContainerController getActionsController() {
    return viewActionsContainer.getController();
  }

  public ContainerController getContentController() {
    return viewContentContainer.getController();
  }

  public boolean isActionsShown() {
    return !mScrollController.isContentShown();
  }

  public void showActions() {
    mScrollController.hideContent(mFlingDuration);
  }

  public boolean isContentShown() {
    return mScrollController.isContentShown();
  }

  public void showContent() {
    mScrollController.showContent(mFlingDuration);
  }

  public void toggleActions() {
    if (isActionsShown())
      showContent();
    else
      showActions();
  }

  public void setSpacingType(int type) {
    if (mSpacingType == type)
      return;

    if (type != SPACING_RIGHT_OFFSET && type != SPACING_ACTIONS_WIDTH)
      return;

    if (DEBUG)
      Log.d(TAG, "- spacing type: " + type);

    mSpacingType = type;
    mForceRefresh = true;
    requestLayout();
  }

  public int getSpacingType() {
    return mSpacingType;
  }

  public void setSpacingWidth(int width) {
    if (mSpacing == width)
      return;

    if (DEBUG)
      Log.d(TAG, "- spacing width: " + width);

    mSpacing = width;
    mForceRefresh = true;
    requestLayout();
  }

  public int getSpacingWidth() {
    return mSpacing;
  }

  public void setActionsSpacingWidth(int width) {
    if (mActionsSpacing == width)
      return;

    mActionsSpacing = width;
    mForceRefresh = true;
    requestLayout();
  }

  public int getActionsSpacingWidth() {
    return mActionsSpacing;
  }

  public void setShadowVisible(boolean visible) {
    viewShadow.setVisibility(visible ? VISIBLE : GONE);
    mForceRefresh = true;
    requestLayout();
  }

  public boolean isShadowVisible() {
    return viewShadow.getVisibility() == VISIBLE;
  }

  public void setShadowWidth(int width) {
    if (mShadowWidth == width)
      return;

    if (DEBUG)
      Log.d(TAG, "- shadow width: " + width);

    mShadowWidth = width;
    viewShadow.getLayoutParams().width = mShadowWidth;
    mForceRefresh = true;
    requestLayout();
  }

  public int getShadowWidth() {
    return mShadowWidth;
  }

  public void setFlingDuration(int duration) {
    mFlingDuration = duration;
  }

  public int getFlingDuration() {
    return mFlingDuration;
  }

  public void setFadeType(int type) {
    if (type != FADE_NONE && type != FADE_ACTIONS && type != FADE_CONTENT && type != FADE_BOTH)
      return;

    mFadeType = type;
    updateScrollFactor();
  }

  public int getFadeType() {
    return mFadeType;
  }

  public void setFadeValue(int value) {
    if (value < 0)
      value = 0;
    else if (value > 255)
      value = 255;

    mFadeValue = value;
    updateScrollFactor();
  }

  public int getFadeValue() {
    return mFadeValue;
  }

  public boolean isSwipingEnabled() {
    return isSwipingEnabled;
  }

  public void setSwipingEnabled(boolean enabled) {
    isSwipingEnabled = enabled;
  }

  public void setSwipingType(int type) {
    if (type != SWIPING_ALL && type != SWIPING_EDGE)
      return;

    mSwipeType = type;
  }

  public int getSwipingType() {
    return mSwipeType;
  }

  public void setSwipingEdgeWidth(int width) {
    mSwipeEdgeWidth = width;
  }

  public int getSwipingEdgeWidth() {
    return mSwipeEdgeWidth;
  }

  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    if (!isSwipingEnabled)
      return false;

    mGestureDetector.onTouchEvent(ev);

    final int action = ev.getAction();
    if (action == MotionEvent.ACTION_UP) {
      if (mScrollController.onUp(ev))
        return true;
    }

    return mScrollController.isHandled();
  }

  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    if (!isSwipingEnabled)
      return false;

    mGestureDetector.onTouchEvent(ev);

    final int action = ev.getAction();
    if (action == MotionEvent.ACTION_UP) {
      if (mScrollController.onUp(ev))
        return true;
    }

    // whether we should handle all following events by our view
    // and don't allow children to get them
    return mScrollController.isHandled();
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    final int width = MeasureSpec.getSize(widthMeasureSpec);
    final int height = MeasureSpec.getSize(heightMeasureSpec);

    if (DEBUG)
      Log.d(TAG, "width: " + width + " height: " + height);

    final int childrenCount = getChildCount();
    for (int i=0; i<childrenCount; ++i) {
      final View v = getChildAt(i);
      if (v == viewActionsContainer) {
        // setting size of actions according to spacing parameters
        if (mSpacingType == SPACING_ACTIONS_WIDTH)
          viewActionsContainer.measure(MeasureSpec.makeMeasureSpec(mSpacing, MeasureSpec.EXACTLY), heightMeasureSpec);
        else // all other situations are handled as SPACING_RIGHT_OFFSET
          viewActionsContainer.measure(MeasureSpec.makeMeasureSpec(width - mSpacing, MeasureSpec.EXACTLY), heightMeasureSpec);
      } else if (v == viewContentContainer) {
        final int shadowWidth = isShadowVisible() ? mShadowWidth : 0;
        final int contentWidth = MeasureSpec.getSize(widthMeasureSpec) - mActionsSpacing + shadowWidth;
        v.measure(MeasureSpec.makeMeasureSpec(contentWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
      } else {
        v.measure(widthMeasureSpec, heightMeasureSpec);
      }
    }

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  }

  @SuppressLint("DrawAllocation")
  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    if (DEBUG) {
      final Rect layout = new Rect(l, t, r, b);
      Log.d(TAG, "layout: " + layout.toShortString());
    }

    // putting every child view to top-left corner
    final int childrenCount = getChildCount();
    for (int i=0; i<childrenCount; ++i) {
      final View v = getChildAt(i);
      if (v == viewContentContainer) {
        final int shadowWidth = isShadowVisible() ? mShadowWidth : 0;
        v.layout(mActionsSpacing - shadowWidth, 0, mActionsSpacing + v.getMeasuredWidth(), v.getMeasuredHeight());
      } else {
        v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
      }
    }

    if (mForceRefresh) {
      mForceRefresh = false;
      mScrollController.init();
    }
  }

  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    // set correct position of content view after view size was changed
    if (w != oldw || h != oldh) {
      mScrollController.init();
    }
  }

  private void updateScrollFactor() {
    if (viewActionsContainer == null || viewContentContainer == null)
      return;

    final float scrollFactor = mScrollController.getScrollFactor();
    final boolean isOpening = mScrollController.isOpening();
    final boolean enableEffects = mScrollController.isEffectsEnabled();

    final int actionsFadeFactor;
    if ((mFadeType & FADE_ACTIONS) == FADE_ACTIONS) {
      actionsFadeFactor = (int) (scrollFactor * mFadeValue);
    } else {
      actionsFadeFactor = 0;
    }
    viewActionsContainer.getController().onScroll(scrollFactor, actionsFadeFactor, isOpening, enableEffects);

    final int contentFadeFactor;
    if ((mFadeType & FADE_CONTENT) == FADE_CONTENT) {
      contentFadeFactor = (int) ((1f - scrollFactor) * mFadeValue);
    } else {
      contentFadeFactor = 0;
    }
    viewContentContainer.getController().onScroll(1f - scrollFactor, contentFadeFactor, isOpening, enableEffects);
  }

  public static class SavedState extends BaseSavedState {
    /**
     * Indicates whether content was shown while saving state.
     */
    private boolean isContentShown;

    /**
     * Spacing type.
     */
    private int mSpacingType = SPACING_RIGHT_OFFSET;
    /**
     * Value of spacing to use.
     */
    private int mSpacing;

    /**
     * Value of actions container spacing to use.
     */
    private int mActionsSpacing;

    /**
     * Indicates whether shadow is visible.
     */
    private boolean isShadowVisible;

    /**
     * Value of shadow width.
     */
    private int mShadowWidth = 0;

    /**
     * Indicates whether swiping is enabled or not.
     */
    private boolean isSwipingEnabled = true;

    /**
     * Indicates how long flinging will take time in milliseconds.
     */
    private int mFlingDuration = 250;

    /**
     * Fade type.
     */
    private int mFadeType = FADE_NONE;
    /**
     * Max fade value.
     */
    private int mFadeValue;

    /**
     * Swiping type.
     */
    private int mSwipeType = FADE_NONE;
    /**
     * Swiping edge width.
     */
    private int mSwipeEdgeWidth;

    public SavedState(Parcelable superState) {
      super(superState);
    }

    public void writeToParcel(Parcel out, int flags) {
      super.writeToParcel(out, flags);

      out.writeInt(isContentShown ? 1 : 0);
      out.writeInt(mSpacingType);
      out.writeInt(mSpacing);
      out.writeInt(mActionsSpacing);
      out.writeInt(isShadowVisible ? 1 : 0);
      out.writeInt(mShadowWidth);
      out.writeInt(isSwipingEnabled ? 1 : 0);
      out.writeInt(mFlingDuration);
      out.writeInt(mFadeType);
      out.writeInt(mFadeValue);
      out.writeInt(mSwipeType);
      out.writeInt(mSwipeEdgeWidth);
    }

    public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
      public SavedState[] newArray(int size) {
        return new SavedState[size];
      }

      @Override
      public SavedState createFromParcel(Parcel source) {
        return new SavedState(source);
      }
    };

    SavedState(Parcel in) {
      super(in);

      isContentShown = in.readInt() == 1;
      mSpacingType = in.readInt();
      mSpacing = in.readInt();
      mActionsSpacing = in.readInt();
      isShadowVisible  = in.readInt() == 1;
      mShadowWidth = in.readInt();
      isSwipingEnabled = in.readInt() == 1;
      mFlingDuration = in.readInt();
      mFadeType = in.readInt();
      mFadeValue = in.readInt();
      mSwipeType = in.readInt();
      mSwipeEdgeWidth = in.readInt();
    }
  }

  /**
   * Used to handle scrolling events and scroll content container
   * on top of actions one.
   * @author steven
   *
   */
  private class ContentScrollController implements GestureDetector.OnGestureListener, Runnable {
    /**
     * Used to auto-scroll to closest bound on touch up event.
     */
    private final Scroller mScroller;
    /**
     * Used to fling to after fling touch event.
     */
    private final Scroller mEffectsScroller;

    // using Boolean object to initialize while first scroll event
    private Boolean mHandleEvent = null;

    /**
     * Indicates whether we need initialize position of view after measuring is finished.
     */
    private boolean isContentShown = true;

    private boolean isFlinging = false;

    private boolean isEffectsEnabled = false;

    public ContentScrollController(Scroller scroller, Scroller effectsScroller) {
      mScroller = scroller;
      mEffectsScroller = effectsScroller;
    }

    /**
     * Initializes visibility of content after views measuring is finished.
     */
    public void init() {
      if (DEBUG)
        Log.d(TAG, "Scroller: init");

      if (isContentShown)
        showContent(0);
      else
        hideContent(0);

      updateScrollFactor();
    }

    /**
     * Returns handling lock value. It indicates whether all events
     * should be marked as handled.
     * @return
     */
    public boolean isHandled() {
      return mHandleEvent != null && mHandleEvent;
    }

    public boolean isSwipeFinished() {
      if (!mScroller.isFinished()) {
        return false;
      }

      if (!mEffectsScroller.isFinished()) {
        return false;
      }

      final int x = viewContentContainer.getScrollX();
      if (isContentShown && x != 0)
        return false;

      if (!isContentShown && x != -getRightBound())
        return false;

      return true;
    }

    public boolean isOpening() {
      if (!mScroller.isFinished()) {
        return mScroller.getStartX() > mScroller.getFinalX();
      }

      if (!mEffectsScroller.isFinished()) {
        return mEffectsScroller.getStartX() > mEffectsScroller.getFinalX();
      }

      return !isContentShown;
    }

    public boolean isEffectsEnabled() {
      return isEffectsEnabled;
    }

    @Override
    public boolean onDown(MotionEvent e) {
      mHandleEvent = null;
      reset();
      return false;
    }

    public boolean onUp(MotionEvent e) {
      if (isSwipeFinished())
        return false;

      mHandleEvent = null;
      completeScrolling();
      return true;
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
      return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {
      // No-op
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
        float distanceY) {

      isFlinging = false;
      isEffectsEnabled = false;

      reset();

      // if there is first scroll event after touch down
      if (mHandleEvent == null) {
        if (Math.abs(distanceX) < Math.abs(distanceY)) {
          // if first event is more scroll by Y axis than X one
          // ignore all events until event up
          mHandleEvent = Boolean.FALSE;
        } else {
          final int contentLeftBound = viewContentContainer.getLeft() - viewContentContainer.getScrollX() + mShadowWidth;
          final int firstTouchX = (int) e1.getX();

          if (DEBUG) {
            Log.d(TAG, "Scroller: first touch: " + firstTouchX + ", " + e1.getY());
            Log.d(TAG, "Content left bound: " + contentLeftBound);
          }

          // if content is not shown we handle all horizontal swipes
          // it content shown and there is edge mode we should check start
          // swiping area first
          if (mSwipeType == SWIPING_ALL
              || (isContentShown() && firstTouchX <= mSwipeEdgeWidth
              || (!isContentShown() && firstTouchX >= contentLeftBound))) {
            // handle all events of scrolling by X axis
            mHandleEvent = Boolean.TRUE;
            scrollBy((int) distanceX);
          } else {
            mHandleEvent = Boolean.FALSE;
          }
        }
      } else if (mHandleEvent) {
        // it is not first event we should handle as scrolling by X axis
        scrollBy((int) distanceX);
      }

      return mHandleEvent;
    }

    @Override
    public void onLongPress(MotionEvent e) {
      // No-op
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
        float velocityY) {

      if (!mHandleEvent) {
        return false;
      }

      final float absVelocityX = Math.abs(velocityX);
      if (absVelocityX <= Math.abs(velocityY))
        return false;

      if (absVelocityX < FLING_MIN)
        return false;

      isFlinging = true;
      if (velocityX < 0)
        showContent(mFlingDuration);
      else
        hideContent(mFlingDuration);

      return true;
    }

    public boolean isContentShown() {
      return isContentShown;
    }

    public void hideContent(int duration) {
      if (DEBUG)
        Log.d(TAG, "Scroller: hide content by " + duration + "ms");

      isContentShown = false;
      if (viewContentContainer.getMeasuredWidth() == 0 || viewContentContainer.getMeasuredHeight() == 0) {
        return;
      }

      scroll(false, duration);
    }

    public void showContent(int duration) {
      if (DEBUG)
        Log.d(TAG, "Scroller: show content by " + duration + "ms");

      isContentShown = true;
      if (viewContentContainer.getMeasuredWidth() == 0 || viewContentContainer.getMeasuredHeight() == 0) {
        return;
      }

      scroll(true, duration);
    }

    public float getScrollFactor() {
      return 1f + (float) viewContentContainer.getScrollX() / (float) getRightBound();
    }

    /**
     * Resets scroller controller. Stops flinging on current position.
     */
    public void reset() {
      if (DEBUG)
        Log.d(TAG, "Scroller: reset");

      if (!mScroller.isFinished()) {
        mScroller.forceFinished(true);
      }
      if (!mEffectsScroller.isFinished()) {
        mEffectsScroller.forceFinished(true);
      }
    }

    /**
     * Starts auto-scrolling to bound which is closer to current position.
     */
    private void completeScrolling() {
      // preventing override of fling effect
      if (!mScroller.isFinished() || !mEffectsScroller.isFinished())
        return;

      final int startX = viewContentContainer.getScrollX();

      final int rightBound = getRightBound();
      final int middle = -rightBound / 2;
      if (startX > middle) {
        showContent(mFlingDuration);
      } else {
        hideContent(mFlingDuration);
      }
    }

    private void scroll(boolean showContent, int duration) {
      reset();

      final int startX = viewContentContainer.getScrollX();
      final int dx = showContent ? -startX : -getRightBound() - startX;
      if (DEBUG)
        Log.d(TAG, "start scroller at " + startX + " for " + dx + " by " + duration);

      if (duration <= 0) {
        viewContentContainer.scrollBy(dx, 0);
        return;
      }

      isEffectsEnabled = startEffects(dx < 0, isFlinging);
      if (isEffectsEnabled)
        mEffectsScroller.startScroll(startX, 0, dx, 0, duration);
      else
        mScroller.startScroll(startX, 0, dx, 0, duration);

      if (mOnActionsContentListener != null)
        mOnActionsContentListener.onContentStateInAction(ActionsContentView.this, isContentShown);

      viewContentContainer.post(this);
    }

    /**
     * Scrolling content view according by given value.
     * @param dx
     */
    private void scrollBy(int dx) {
      final int x = viewContentContainer.getScrollX();

      isEffectsEnabled = startEffects(!isContentShown, false);

      final int scrollBy;
      if (dx < 0) { // scrolling right
        final int rightBound = getRightBound();
        if (x + dx < -rightBound)
          scrollBy = -rightBound - x;
        else
          scrollBy = dx;
      } else { // scrolling left
        // don't scroll if we are at left bound
        if (x == 0)
          return;

        if (x + dx > 0)
          scrollBy = -x;
        else
          scrollBy = dx;
      }

      if (DEBUG)
        Log.d(TAG, "scroll from " + x + " by " + dx + " [" + scrollBy + "]");

      viewContentContainer.scrollBy(scrollBy, 0);
    }

    /**
     * Processes auto-scrolling to bound which is closer to current position.
     */
    @Override
    public void run() {
      final Scroller scroller = isEffectsEnabled() ? mEffectsScroller : mScroller;
      if (scroller.isFinished()) {
        if (DEBUG)
          Log.d(TAG, "scroller is finished, done with fling");
        if (mOnActionsContentListener != null)
          mOnActionsContentListener.onContentStateChanged(ActionsContentView.this, isContentShown);
        return;
      }


      final boolean more = scroller.computeScrollOffset();
      final int x = scroller.getCurrX();
      viewContentContainer.scrollTo(x, 0);

      if (more) {
        viewContentContainer.post(this);
      } else {
        if (mOnActionsContentListener != null)
          mOnActionsContentListener.onContentStateChanged(ActionsContentView.this, isContentShown);
      }
    }

    /**
     * Returns right bound (limit) for scroller.
     * @return right bound (limit) for scroller.
     */
    private int getRightBound() {
      if (mSpacingType == SPACING_ACTIONS_WIDTH) {
        return mSpacing - mActionsSpacing;
      } else { // all other situations are handled as SPACING_RIGHT_OFFSET
        return getWidth() - mSpacing - mActionsSpacing;
      }
    }

    private boolean startEffects(boolean isOpening, boolean isFlinging) {
      final boolean enableEffects;

      if (mEffects == EFFECTS_NONE) {
        enableEffects = false;
      } else if (!isFlinging && (mEffects & EFFECTS_SCROLL) > 0) {
        if (isOpening && (mEffects & EFFECTS_SCROLL_OPENING) == EFFECTS_SCROLL_OPENING)
          enableEffects = true;
        else if (!isOpening && (mEffects & EFFECTS_SCROLL_CLOSING) == EFFECTS_SCROLL_CLOSING)
          enableEffects = true;
        else
          enableEffects = false;
      } else if (isFlinging && (mEffects & EFFECTS_FLING) > 0) {
        if (isOpening && (mEffects & EFFECTS_FLING_OPENING) == EFFECTS_FLING_OPENING)
          enableEffects = true;
        else if (!isOpening && (mEffects & EFFECTS_FLING_CLOSING) == EFFECTS_FLING_CLOSING)
          enableEffects = true;
        else
          enableEffects = false;
      } else {
        enableEffects = false;
      }

      return enableEffects;
    }
  };
}




Java Source Code List

com.nirhart.parallaxscroll.BuildConfig.java
com.nirhart.parallaxscroll.BuildConfig.java
com.nirhart.parallaxscroll.views.ParallaxExpandableListView.java
com.nirhart.parallaxscroll.views.ParallaxListViewHelper.java
com.nirhart.parallaxscroll.views.ParallaxListView.java
com.nirhart.parallaxscroll.views.ParallaxScrollView.java
com.nirhart.parallaxscroll.views.ParallaxedView.java
org.arasthel.googlenavdrawermenu.adapters.GoogleNavigationDrawerAdapter.java
org.arasthel.googlenavdrawermenu.utils.Utils.java
org.arasthel.googlenavdrawermenu.views.CheckableImageView.java
org.arasthel.googlenavdrawermenu.views.CheckableRelativeLayout.java
org.arasthel.googlenavdrawermenu.views.CheckedTextView.java
org.arasthel.googlenavdrawermenu.views.GoogleNavigationDrawer.java
shared.ui.actionscontentview.ActionsContentView.java
shared.ui.actionscontentview.ActionsLayout.java
shared.ui.actionscontentview.BaseContainerController.java
shared.ui.actionscontentview.BuildConfig.java
shared.ui.actionscontentview.ContainerController.java
shared.ui.actionscontentview.ContentLayout.java
shared.ui.actionscontentview.EffectsController.java
taz.starz.footynews.MainActivity.java
taz.starz.footynews.OfflineReadActivity.java
taz.starz.footynews.SplashScreen.java
taz.starz.footynews.ViewOfflineActivity.java
taz.starz.footynews.ViewStoryActivity.java
taz.starz.footynews.adapter.CustomListAdapter.java
taz.starz.footynews.adapter.CustomOfflineReaderAdapter.java
taz.starz.footynews.fragments.BundesLigaFragment.java
taz.starz.footynews.fragments.LigaBBVAFragment.java
taz.starz.footynews.fragments.PremierLeagueFragment.java
taz.starz.footynews.fragments.SerieAFragment.java
taz.starz.footynews.library.DatabaseHandler.java
taz.starz.footynews.library.JSONParser.java
taz.starz.footynews.library.NetworkFunctions.java
taz.starz.footynews.library.NewsItem.java
taz.starz.footynews.library.SharedPref.java