Android Open Source - GuiLib Photo View Attacher






From Project

Back to project page GuiLib.

License

The source code is released under:

Apache License

If you think the Android project GuiLib 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 2011, 2012 Chris Banes./* www .j av a2s.c om*/
 *
 * 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 uk.co.senab.photoview;

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;

public class PhotoViewAttacher implements View.OnTouchListener, VersionedGestureDetector.OnGestureListener,
    GestureDetector.OnDoubleTapListener, OnGlobalLayoutListener {

  static final boolean DEBUG = false;
  static final String LOG_TAG = "PhotoViewAttacher";

  /**
   * Interface definition for a callback to be invoked when the internal Matrix has changed for this View.
   * 
   * @author Chris Banes
   */
  public static interface OnMatrixChangedListener {
    /**
     * Callback for when the Matrix displaying the Drawable has changed. This could be because the View's bounds
     * have changed, or the user has zoomed.
     * 
     * @param rect
     *            - Rectangle displaying the Drawable's new bounds.
     */
    void onMatrixChanged(RectF rect);
  }

  /**
   * Interface definition for a callback to be invoked when the Photo is tapped with a single tap.
   * 
   * @author Chris Banes
   */
  public static interface OnPhotoTapListener {

    /**
     * A callback to receive where the user taps on a photo. You will only receive a callback if the user taps on
     * the actual photo, tapping on 'whitespace' will be ignored.
     * 
     * @param view
     *            - View the user tapped
     * @param x
     *            - where the user tapped from the left, as percentage of the Drawable width.
     * @param y
     *            - where the user tapped from the top, as percentage of the Drawable height.
     */
    void onPhotoTap(View view, float x, float y);
  }

  private class FlingRunnable implements Runnable {

    private final ScrollerProxy mScroller;
    private int mCurrentX, mCurrentY;

    public FlingRunnable() {
      Context context = mImageView.getContext();
      mScroller = ScrollerProxy.getScroller(context);
    }

    public void fling(int velocityX, int velocityY) {
      final RectF rect = getDisplayRect();
      if (null == rect) {
        return;
      }

      final int viewHeight = mImageView.getHeight();
      final int viewWidth = mImageView.getWidth();
      final int startX = Math.round(-rect.left);
      final int minX, maxX, minY, maxY;

      if (viewWidth < rect.width()) {
        minX = 0;
        maxX = Math.round(rect.width() - viewWidth);
      } else {
        minX = maxX = startX;
      }

      final int startY = Math.round(-rect.top);
      if (viewHeight < rect.height()) {
        minY = 0;
        maxY = Math.round(rect.height() - viewHeight);
      } else {
        minY = maxY = startY;
      }

      mCurrentX = startX;
      mCurrentY = startY;

      if (DEBUG) {
        Log.d(LOG_TAG, "fling. StartX:" + startX + " StartY:" + startY + " MaxX:" + maxX + " MaxY:" + maxY);
      }

      // If we actually can move, fling the scroller
      if (startX != maxX || startY != maxY) {
        mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, 0, 0);
      }
    }

    @Override
    public void run() {
      if (mScroller.computeScrollOffset()) {

        final int newX = mScroller.getCurrX();
        final int newY = mScroller.getCurrY();

        if (DEBUG) {
          Log.d(LOG_TAG, "fling run(). CurrentX:" + mCurrentX + " CurrentY:" + mCurrentY + " NewX:" + newX
              + " NewY:" + newY);
        }

        mSuppMatrix.postTranslate(mCurrentX - newX, mCurrentY - newY);
        setImageViewMatrix(getDisplayMatrix());

        mCurrentX = newX;
        mCurrentY = newY;

        // Post On animation
        Compat.postOnAnimation(mImageView, this);
      }
    }

    public void cancelFling() {
      if (DEBUG) {
        Log.d(LOG_TAG, "Cancel Fling");
      }
      mScroller.forceFinished(true);
    }
  }

  private class AnimatedZoomRunnable implements Runnable {

    // These are 'postScale' values, means they're compounded each iteration
    static final float ANIMATION_SCALE_PER_ITERATION_IN = 1.07f;
    static final float ANIMATION_SCALE_PER_ITERATION_OUT = 0.93f;

    private final float mFocalX, mFocalY;
    private final float mTargetZoom;
    private final float mDeltaScale;

    public AnimatedZoomRunnable(final float currentZoom, final float targetZoom, final float focalX,
        final float focalY) {
      mTargetZoom = targetZoom;
      mFocalX = focalX;
      mFocalY = focalY;

      if (currentZoom < targetZoom) {
        mDeltaScale = ANIMATION_SCALE_PER_ITERATION_IN;
      } else {
        mDeltaScale = ANIMATION_SCALE_PER_ITERATION_OUT;
      }
    }

    public void run() {
      mSuppMatrix.postScale(mDeltaScale, mDeltaScale, mFocalX, mFocalY);
      checkAndDisplayMatrix();

      final float currentScale = getScale();

      if ((mDeltaScale > 1f && currentScale < mTargetZoom) || (mDeltaScale < 1f && mTargetZoom < currentScale)) {
        // We haven't hit our target scale yet, so post ourselves again
        Compat.postOnAnimation(mImageView, this);

      } else {
        // We've scaled past our target zoom, so calculate the
        // necessary scale so we're back at target zoom
        final float delta = mTargetZoom / currentScale;
        mSuppMatrix.postScale(delta, delta, mFocalX, mFocalY);
        checkAndDisplayMatrix();
      }
    }
  }

  private static boolean isSupportedScaleType(final ScaleType scaleType) {
    if (null == scaleType) {
      return false;
    }

    switch (scaleType) {
    case MATRIX:
      throw new IllegalArgumentException(scaleType.name() + " is not supported in PhotoView");

    default:
      return true;
    }
  }

  static final int EDGE_NONE = -1;
  static final int EDGE_LEFT = 0;
  static final int EDGE_RIGHT = 1;
  static final int EDGE_BOTH = 2;

  private static final float MAX_ZOOM = 8.0f;
  private static final float MID_ZOOM = 1.75f;
  private static final float MIN_ZOOM = 1.0f;

  // Gesture Detectors
  private GestureDetector mGestureDetector;
  private VersionedGestureDetector mScaleDragDetector;

  // These are set so we don't keep allocating them on the heap
  private final Matrix mBaseMatrix = new Matrix();
  private final Matrix mDrawMatrix = new Matrix();
  private final Matrix mSuppMatrix = new Matrix();
  private final RectF mDisplayRect = new RectF();

  // Listeners
  private OnMatrixChangedListener mMatrixChangeListener;
  private OnPhotoTapListener mPhotoTapListener;

  // Saves us allocating a new float[] when getValue is called
  private final float[] mMatrixValues = new float[9];

  private int mScrollEdge = EDGE_BOTH;
  private boolean mZoomEnabled;
  private ScaleType mScaleType = ScaleType.FIT_CENTER;

  private FlingRunnable mCurrentFlingRunnable;

  private final ImageView mImageView;

  private int mIvTop, mIvRight, mIvBottom, mIvLeft;

  public PhotoViewAttacher(ImageView imageView) {
    mImageView = imageView;
    mImageView.setOnTouchListener(this);
    mImageView.getViewTreeObserver().addOnGlobalLayoutListener(this);

    if (!imageView.isInEditMode()) {
      // Create Gesture Detectors...
      // When we're not in the Graphical Layout Editor
      mScaleDragDetector = VersionedGestureDetector.newInstance(mImageView.getContext(), this);
      mGestureDetector = new GestureDetector(mImageView.getContext(),
          new GestureDetector.SimpleOnGestureListener());
      mGestureDetector.setOnDoubleTapListener(this);
    }

    // Make sure we using MATRIX Scale Type
    setImageViewScaleTypeMatrix();

    if (!imageView.isInEditMode()) {
      // Finally, update the UI so that we're zoomable
      // If we're not in the Graphical Layout Editor
      setZoomable(true);
    }
  }

  /**
   * Returns true if the PhotoView is set to allow zooming of Photos.
   * 
   * @return true if the PhotoView allows zooming.
   */
  public final boolean canZoom() {
    return mZoomEnabled;
  }

  /**
   * Gets the Display Rectangle of the currently displayed Drawable. The Rectangle is relative to this View and
   * includes all scaling and translations.
   * 
   * @return - RectF of Displayed Drawable
   */
  public final RectF getDisplayRect() {
    checkMatrixBounds();
    return getDisplayRect(getDisplayMatrix());
  }

  /**
   * Returns the current scale value
   * 
   * @return float - current scale value
   */
  public final float getScale() {
    return getValue(mSuppMatrix, Matrix.MSCALE_X);
  }

  /**
   * Return the current scale type in use by the ImageView.
   */
  public final ScaleType getScaleType() {
    return mScaleType;
  }

  public final boolean onDoubleTap(MotionEvent ev) {
    try {
      float scale = getScale();
      float x = ev.getX();
      float y = ev.getY();

      if (scale < MID_ZOOM) {
        zoomTo(MID_ZOOM, x, y);
      } else if (scale >= MID_ZOOM && scale < MAX_ZOOM) {
        zoomTo(MAX_ZOOM, x, y);
      } else {
        zoomTo(MIN_ZOOM, x, y);
      }
    } catch (ArrayIndexOutOfBoundsException e) {
      // Can sometimes happen when getX() and getY() is called
    }

    return true;
  }

  public final boolean onDoubleTapEvent(MotionEvent e) {
    // Wait for the confirmed onDoubleTap() instead
    return false;
  }

  public final void onDrag(float dx, float dy) {
    if (DEBUG) {
      Log.d(LOG_TAG, String.format("onDrag: dx: %.2f. dy: %.2f", dx, dy));
    }

    if (hasDrawable()) {
      mSuppMatrix.postTranslate(dx, dy);
      checkAndDisplayMatrix();

      /**
       * Here we decide whether to let the ImageView's parent to start taking over the touch event.
       * 
       * We never want the parent to take over if we're scaling. We then check the edge we're on, and the
       * direction of the scroll (i.e. if we're pulling against the edge, aka 'overscrolling', let the parent take
       * over).
       */
      if (!mScaleDragDetector.isScaling()) {
        if (mScrollEdge == EDGE_BOTH || (mScrollEdge == EDGE_LEFT && dx >= 1f)
            || (mScrollEdge == EDGE_RIGHT && dx <= -1f)) {
          mImageView.getParent().requestDisallowInterceptTouchEvent(false);
        }
      }
    }
  }

  @Override
  public final void onFling(float startX, float startY, float velocityX, float velocityY) {
    if (DEBUG) {
      Log.d(LOG_TAG, "onFling. sX: " + startX + " sY: " + startY + " Vx: " + velocityX + " Vy: " + velocityY);
    }

    if (hasDrawable()) {
      mCurrentFlingRunnable = new FlingRunnable();
      mCurrentFlingRunnable.fling((int) velocityX, (int) velocityY);
      mImageView.post(mCurrentFlingRunnable);
    }
  }

  @Override
  public final void onGlobalLayout() {
    if (mZoomEnabled) {

      final int top = mImageView.getTop();
      final int right = mImageView.getRight();
      final int bottom = mImageView.getBottom();
      final int left = mImageView.getLeft();

      /**
       * We need to check whether the ImageView's bounds have changed. This would be easier if we targeted API 11+
       * as we could just use View.OnLayoutChangeListener. Instead we have to replicate the work, keeping track of
       * the ImageView's bounds and then checking if the values change.
       */
      if (top != mIvTop || bottom != mIvBottom || left != mIvLeft || right != mIvRight) {
        // Update our base matrix, as the bounds have changed
        updateBaseMatrix(mImageView.getDrawable());

        // Update values as something has changed
        mIvTop = top;
        mIvRight = right;
        mIvBottom = bottom;
        mIvLeft = left;
      }
    }
  }

  public final void onScale(float scaleFactor, float focusX, float focusY) {
    if (DEBUG) {
      Log.d(LOG_TAG, String.format("onScale: scale: %.2f. fX: %.2f. fY: %.2f", scaleFactor, focusX, focusY));
    }

    if (hasDrawable() && (getScale() < MAX_ZOOM || scaleFactor < 1f)) {
      mSuppMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY);
      checkAndDisplayMatrix();
    }
  }

  public final boolean onSingleTapConfirmed(MotionEvent e) {
    if (null != mPhotoTapListener) {
      final RectF displayRect = getDisplayRect();

      if (null != displayRect) {
        final float x = e.getX(), y = e.getY();

        // Check to see if the user tapped on the photo
        if (displayRect.contains(x, y)) {

          float xResult = (x - displayRect.left) / displayRect.width();
          float yResult = (y - displayRect.top) / displayRect.height();

          mPhotoTapListener.onPhotoTap(mImageView, xResult, yResult);
          return true;
        }
      }
    }

    return false;
  }

  @Override
  public final boolean onTouch(View v, MotionEvent ev) {
    if (mZoomEnabled) {

      switch (ev.getAction()) {
      case MotionEvent.ACTION_DOWN:
        // First, disable the Parent from intercepting the touch
        // event
        v.getParent().requestDisallowInterceptTouchEvent(true);

        // If we're flinging, and the user presses down, cancel
        // fling
        cancelFling();
        break;

      case MotionEvent.ACTION_CANCEL:
      case MotionEvent.ACTION_UP:
        // If the user has zoomed less than MIN_ZOOM, zoom back
        // to 1.0f
        if (getScale() < MIN_ZOOM) {
          RectF rect = getDisplayRect();
          if (null != rect) {
            v.post(new AnimatedZoomRunnable(getScale(), MIN_ZOOM, rect.centerX(), rect.centerY()));
          }
          return true;
        }
        break;
      }

      // Check to see if the user double tapped
      if (null != mGestureDetector && mGestureDetector.onTouchEvent(ev)) {
        return true;
      }

      // Finally, try the Scale/Drag detector
      if (null != mScaleDragDetector && mScaleDragDetector.onTouchEvent(ev)) {
        return true;
      }
    }

    return false;
  }

  /**
   * Controls how the image should be resized or moved to match the size of the ImageView. Any scaling or panning will
   * happen within the confines of this {@link ScaleType}.
   * 
   * @param scaleType
   *            - The desired scaling mode.
   */
  public final void setScaleType(ScaleType scaleType) {
    if (isSupportedScaleType(scaleType) && scaleType != mScaleType) {
      mScaleType = scaleType;

      // Finally update
      update();
    }
  }

  /**
   * Register a callback to be invoked when the Matrix has changed for this View. An example would be the user panning
   * or scaling the Photo.
   * 
   * @param listener
   *            - Listener to be registered.
   */
  public final void setOnMatrixChangeListener(OnMatrixChangedListener listener) {
    mMatrixChangeListener = listener;
  }

  /**
   * Register a callback to be invoked when the Photo displayed by this View is tapped with a single tap.
   * 
   * @param listener
   *            - Listener to be registered.
   */
  public final void setOnPhotoTapListener(OnPhotoTapListener listener) {
    mPhotoTapListener = listener;
  }

  /**
   * Allows you to enable/disable the zoom functionality on the ImageView. When disable the ImageView reverts to using
   * the FIT_CENTER matrix.
   * 
   * @param zoomable
   *            - Whether the zoom functionality is enabled.
   */
  public final void setZoomable(boolean zoomable) {
    mZoomEnabled = zoomable;
    update();
  }

  public final void update() {
    if (mZoomEnabled) {
      // Make sure we using MATRIX Scale Type
      setImageViewScaleTypeMatrix();

      // Update the base matrix using the current drawable
      updateBaseMatrix(mImageView.getDrawable());
    } else {
      // Reset the Matrix...
      resetMatrix();
    }
  }

  /**
   * Zooms to the specified scale, around the focal point given.
   * 
   * @param scale
   *            - Scale to zoom to
   * @param focalX
   *            - X Focus Point
   * @param focalY
   *            - Y Focus Point
   */
  public final void zoomTo(float scale, float focalX, float focalY) {
    mImageView.post(new AnimatedZoomRunnable(getScale(), scale, focalX, focalY));
  }

  public Matrix getDisplayMatrix() {
    mDrawMatrix.set(mBaseMatrix);
    mDrawMatrix.postConcat(mSuppMatrix);
    return mDrawMatrix;
  }

  private void cancelFling() {
    if (null != mCurrentFlingRunnable) {
      mCurrentFlingRunnable.cancelFling();
      mCurrentFlingRunnable = null;
    }
  }

  /**
   * Helper method that simply checks the Matrix, and then displays the result
   */
  private void checkAndDisplayMatrix() {
    checkMatrixBounds();
    setImageViewMatrix(getDisplayMatrix());
  }

  private void checkImageViewScaleType() {
    /**
     * PhotoView's getScaleType() will just divert to this.getScaleType() so only call if we're not attached to a
     * PhotoView.
     */
    if (!(mImageView instanceof PhotoView)) {
      if (mImageView.getScaleType() != ScaleType.MATRIX) {
        throw new IllegalStateException(
            "The ImageView's ScaleType has been changed since attaching a PhotoViewAttacher");
      }
    }
  }

  private void checkMatrixBounds() {
    final RectF rect = getDisplayRect(getDisplayMatrix());
    if (null == rect) {
      return;
    }

    final float height = rect.height(), width = rect.width();
    float deltaX = 0, deltaY = 0;

    final int viewHeight = mImageView.getHeight();
    if (height <= viewHeight) {
      switch (mScaleType) {
      case FIT_START:
        deltaY = -rect.top;
        break;
      case FIT_END:
        deltaY = viewHeight - height - rect.top;
        break;
      default:
        deltaY = (viewHeight - height) / 2 - rect.top;
        break;
      }
    } else if (rect.top > 0) {
      deltaY = -rect.top;
    } else if (rect.bottom < viewHeight) {
      deltaY = viewHeight - rect.bottom;
    }

    final int viewWidth = mImageView.getWidth();
    if (width <= viewWidth) {
      switch (mScaleType) {
      case FIT_START:
        deltaX = -rect.left;
        break;
      case FIT_END:
        deltaX = viewWidth - width - rect.left;
        break;
      default:
        deltaX = (viewWidth - width) / 2 - rect.left;
        break;
      }
      mScrollEdge = EDGE_BOTH;
    } else if (rect.left > 0) {
      mScrollEdge = EDGE_LEFT;
      deltaX = -rect.left;
    } else if (rect.right < viewWidth) {
      deltaX = viewWidth - rect.right;
      mScrollEdge = EDGE_RIGHT;
    } else {
      mScrollEdge = EDGE_NONE;
    }

    // Finally actually translate the matrix
    mSuppMatrix.postTranslate(deltaX, deltaY);
  }

  /**
   * Helper method that maps the supplied Matrix to the current Drawable
   * 
   * @param Matrix
   *            - Matrix to map Drawable against
   * @return RectF - Displayed Rectangle
   */
  private RectF getDisplayRect(Matrix matrix) {
    Drawable d = mImageView.getDrawable();
    if (null != d) {
      mDisplayRect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
      matrix.mapRect(mDisplayRect);
      return mDisplayRect;
    }
    return null;
  }

  /**
   * Helper method that 'unpacks' a Matrix and returns the required value
   * 
   * @param matrix
   *            - Matrix to unpack
   * @param whichValue
   *            - Which value from Matrix.M* to return
   * @return float - returned value
   */
  private float getValue(Matrix matrix, int whichValue) {
    matrix.getValues(mMatrixValues);
    return mMatrixValues[whichValue];
  }

  private boolean hasDrawable() {
    return null != mImageView.getDrawable();
  }

  /**
   * Resets the Matrix back to FIT_CENTER, and then displays it.s
   */
  private void resetMatrix() {
    mSuppMatrix.reset();
    setImageViewMatrix(getDisplayMatrix());
    checkMatrixBounds();
  }

  private void setImageViewScaleTypeMatrix() {
    if (mImageView instanceof PhotoView) {
      /**
       * PhotoView sets it's own ScaleType to Matrix, then diverts all calls setScaleType to this.setScaleType.
       * Basically we don't need to do anything here
       */
    } else {
      mImageView.setScaleType(ScaleType.MATRIX);
    }
  }

  public float[] getSuppViewMatrix() {
    mSuppMatrix.getValues(mMatrixValues);
    return mMatrixValues;
  }

  public void setSuppViewMatrix(float[] values) {
    mSuppMatrix.setValues(values);
    checkAndDisplayMatrix();
  }

  public void setImageViewMatrix(Matrix matrix) {
    checkImageViewScaleType();
    mImageView.setImageMatrix(matrix);

    // Call MatrixChangedListener if needed
    if (null != mMatrixChangeListener) {
      RectF displayRect = getDisplayRect(matrix);
      if (null != displayRect) {
        mMatrixChangeListener.onMatrixChanged(displayRect);
      }
    }
  }

  /**
   * Calculate Matrix for FIT_CENTER
   * 
   * @param d
   *            - Drawable being displayed
   */
  private void updateBaseMatrix(Drawable d) {
    if (null == d) {
      return;
    }

    final float viewWidth = mImageView.getWidth();
    final float viewHeight = mImageView.getHeight();
    final int drawableWidth = d.getIntrinsicWidth();
    final int drawableHeight = d.getIntrinsicHeight();

    mBaseMatrix.reset();

    final float widthScale = viewWidth / drawableWidth;
    final float heightScale = viewHeight / drawableHeight;

    if (mScaleType == ScaleType.CENTER) {
      mBaseMatrix.postTranslate((viewWidth - drawableWidth) / 2F, (viewHeight - drawableHeight) / 2F);

    } else if (mScaleType == ScaleType.CENTER_CROP) {
      float scale = Math.max(widthScale, heightScale);
      mBaseMatrix.postScale(scale, scale);
      mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
          (viewHeight - drawableHeight * scale) / 2F);

    } else if (mScaleType == ScaleType.CENTER_INSIDE) {
      float scale = Math.min(1.0f, Math.min(widthScale, heightScale));
      mBaseMatrix.postScale(scale, scale);
      mBaseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2F,
          (viewHeight - drawableHeight * scale) / 2F);

    } else {
      RectF mTempSrc = new RectF(0, 0, drawableWidth, drawableHeight);
      RectF mTempDst = new RectF(0, 0, viewWidth, viewHeight);

      switch (mScaleType) {
      case FIT_CENTER:
        mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.CENTER);
        break;

      case FIT_START:
        mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.START);
        break;

      case FIT_END:
        mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.END);
        break;

      case FIT_XY:
        mBaseMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.FILL);
        break;
      }
    }

    resetMatrix();
  }
}




Java Source Code List

au.com.bytecode.opencsv.CSVReader.java
com.ecloud.pulltozoomview.PullToZoomScrollView.java
com.gandulf.guilib.data.OpenArrayAdapter.java
com.gandulf.guilib.data.OpenFilter.java
com.gandulf.guilib.download.AbstractDownloader.java
com.gandulf.guilib.download.DownloadBroadcastReceiver.java
com.gandulf.guilib.download.DownloaderGinger.java
com.gandulf.guilib.download.DownloaderWrapper.java
com.gandulf.guilib.download.Downloader.java
com.gandulf.guilib.download.MediaScannerWrapper.java
com.gandulf.guilib.download.UnzipIntentService.java
com.gandulf.guilib.listener.CheckableListenable.java
com.gandulf.guilib.listener.OnCheckedChangeListener.java
com.gandulf.guilib.util.ColorUtil.java
com.gandulf.guilib.util.Debug.java
com.gandulf.guilib.util.DefaultTextWatcher.java
com.gandulf.guilib.util.DirectoryFileFilter.java
com.gandulf.guilib.util.FileFileFilter.java
com.gandulf.guilib.util.ListViewCompat.java
com.gandulf.guilib.util.MathUtil.java
com.gandulf.guilib.util.ResUtil.java
com.gandulf.guilib.view.ColorPickerDialog.java
com.gandulf.guilib.view.DynamicListViewEx.java
com.gandulf.guilib.view.HackeyDrawerLayout.java
com.gandulf.guilib.view.SeekBarEx.java
com.gandulf.guilib.view.VersionInfoDialog.java
com.gandulf.guilib.view.ViewScroller.java
com.gandulf.guilib.view.adapter.MultiFragmentPagerAdapter.java
com.getbase.floatingactionbutton.AddFloatingActionButton.java
com.getbase.floatingactionbutton.FloatingActionButton.java
com.getbase.floatingactionbutton.FloatingActionsMenu.java
com.github.amlcurran.showcaseview.AnimationFactory.java
com.github.amlcurran.showcaseview.AnimatorAnimationFactory.java
com.github.amlcurran.showcaseview.ApiUtils.java
com.github.amlcurran.showcaseview.Calculator.java
com.github.amlcurran.showcaseview.NewShowcaseDrawer.java
com.github.amlcurran.showcaseview.OnShowcaseEventListener.java
com.github.amlcurran.showcaseview.ShotStateStore.java
com.github.amlcurran.showcaseview.ShowcaseAreaCalculator.java
com.github.amlcurran.showcaseview.ShowcaseDrawer.java
com.github.amlcurran.showcaseview.ShowcaseView.java
com.github.amlcurran.showcaseview.StandardShowcaseDrawer.java
com.github.amlcurran.showcaseview.TextDrawer.java
com.github.amlcurran.showcaseview.targets.ActionBarReflector.java
com.github.amlcurran.showcaseview.targets.ActionBarViewWrapper.java
com.github.amlcurran.showcaseview.targets.ActionItemTarget.java
com.github.amlcurran.showcaseview.targets.ActionViewTarget.java
com.github.amlcurran.showcaseview.targets.AppCompatReflector.java
com.github.amlcurran.showcaseview.targets.PointTarget.java
com.github.amlcurran.showcaseview.targets.ReflectorFactory.java
com.github.amlcurran.showcaseview.targets.Reflector.java
com.github.amlcurran.showcaseview.targets.SherlockReflector.java
com.github.amlcurran.showcaseview.targets.Target.java
com.github.amlcurran.showcaseview.targets.ViewTarget.java
com.sothree.slidinguppanel.SlidingUpPanelLayout.java
com.sothree.slidinguppanel.ViewDragHelper.java
com.thebnich.floatinghintedittext.FloatingHintEditText.java
com.thebnich.floatinghintedittext.FloatingHintTextView.java
com.wefika.flowlayout.FlowLayout.java
de.hdodenhof.circleimageview.CircleImageView.java
uk.co.senab.photoview.Compat.java
uk.co.senab.photoview.PhotoViewAttacher.java
uk.co.senab.photoview.PhotoView.java
uk.co.senab.photoview.SDK16.java
uk.co.senab.photoview.ScrollerProxy.java
uk.co.senab.photoview.VersionedGestureDetector.java
uk.me.lewisdeane.ldialogs.BaseDialog.java
uk.me.lewisdeane.ldialogs.CustomDialog.java
uk.me.lewisdeane.ldialogs.CustomListAdapter.java