Tuesday, September 16, 2014

Android PanningView with Fadein and Fadeout Animation

Android PanningView with Fadein and Fadeout Animation
This post about PanningView with fade in and fade out the images.
See the below video you can get more idea




Screen Shot






MainActivity.java

package com.iamvijayakumar.panningviewwith;

import android.annotation.SuppressLint;

import android.app.Activity;

import android.graphics.drawable.AnimationDrawable;

import android.os.Bundle;

/**
 *
 *
 *
 * @author iamvijayakumar
 *
 *
 */

@SuppressLint("NewApi")
public class MainActivity extends Activity {

       PanningView mPanningView;

       @SuppressLint("NewApi")
       @Override
       protected void onCreate(Bundle savedInstanceState) {

              super.onCreate(savedInstanceState);

              setContentView(R.layout.activity_main);

              mPanningView = (PanningView) findViewById(R.id.panningView);

              AnimationDrawable animDrawable = new AnimationDrawable();

              animDrawable.addFrame(getResources().getDrawable(R.drawable.images1),

              10000);

              animDrawable.addFrame(getResources().getDrawable(R.drawable.images2),

              10000);

              // For Repeat Animation Make it false

              animDrawable.setOneShot(false);

              animDrawable.setEnterFadeDuration(2000);

              animDrawable.setExitFadeDuration(2000);

              mPanningView.setImageDrawable(animDrawable);

       }

       @Override
       protected void onResume() {

              super.onResume();

              if (mPanningView != null) {

                     mPanningView.startPanning();

              }

       }

}


PanningView.java


package com.iamvijayakumar.panningviewwith;

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.drawable.Drawable;

import android.net.Uri;

import android.util.AttributeSet;

import android.widget.ImageView;

public class PanningView extends ImageView {

       private final PanningViewAttacher mAttacher;

       private int mPanningDurationInMs;

       public PanningView(Context context) {

              this(context, null);

       }

       public PanningView(Context context, AttributeSet attr) {

              this(context, attr, 0);

       }

       public PanningView(Context context, AttributeSet attr, int defStyle) {

              super(context, attr, defStyle);

              readStyleParameters(context, attr);

              super.setScaleType(ScaleType.MATRIX);

              mAttacher = new PanningViewAttacher(this, mPanningDurationInMs);

       }

       /**
        *
        * @param context
        *
        * @param attributeSet
        */

       private void readStyleParameters(Context context, AttributeSet attributeSet) {

              TypedArray a = context.obtainStyledAttributes(attributeSet,

              R.styleable.PanningView);

              try {

                     mPanningDurationInMs = a.getInt(

                     R.styleable.PanningView_panningDurationInMs,

                     PanningViewAttacher.DEFAULT_PANNING_DURATION_IN_MS);

              } finally {

                     a.recycle();

              }

       }

       @Override
       // setImageBitmap calls through to this method
       public void setImageDrawable(Drawable drawable) {

              super.setImageDrawable(drawable);

              stopUpdateStartIfNecessary();

       }

       @Override
       public void setImageResource(int resId) {

              super.setImageResource(resId);

              stopUpdateStartIfNecessary();

       }

       @Override
       public void setImageURI(Uri uri) {

              super.setImageURI(uri);

              stopUpdateStartIfNecessary();

       }

       private void stopUpdateStartIfNecessary() {

              if (null != mAttacher) {

                     boolean wasPanning = mAttacher.isPanning();

                     mAttacher.stopPanning();

                     mAttacher.update();

                     if (wasPanning) {

                           mAttacher.startPanning();

                     }

              }

       }

       @Override
       public void setScaleType(ScaleType scaleType) {

              throw new UnsupportedOperationException(

              "only matrix scaleType is supported");

       }

       @Override
       protected void onDetachedFromWindow() {

              mAttacher.cleanup();

              super.onDetachedFromWindow();

       }

       public void startPanning() {

              mAttacher.startPanning();

       }

       public void stopPanning() {

              mAttacher.stopPanning();

       }

}

PanningViewAttacher.java


package com.iamvijayakumar.panningviewwith;

import android.content.res.Configuration;

import android.graphics.Matrix;

import android.graphics.RectF;

import android.util.Log;

import android.view.ViewTreeObserver;

import android.view.animation.LinearInterpolator;

import android.widget.ImageView;

import com.nineoldandroids.animation.Animator;

import com.nineoldandroids.animation.AnimatorListenerAdapter;

import com.nineoldandroids.animation.ValueAnimator;

import java.lang.ref.WeakReference;

public class PanningViewAttacher implements

ViewTreeObserver.OnGlobalLayoutListener {

       public static final int DEFAULT_PANNING_DURATION_IN_MS = 500;

       private static final String TAG = "PanningViewAttacher";

       private enum Way {

              R2L, L2R, T2B, B2T

       };

       private WeakReference<ImageView> mImageView;

       private int mIvTop, mIvRight, mIvBottom, mIvLeft;

       private ViewTreeObserver mViewTreeObserver;

       private Matrix mMatrix;

       private RectF mDisplayRect = new RectF();

       private ValueAnimator mCurrentAnimator;

       private LinearInterpolator mLinearInterpolator;

       private boolean mIsPortrait;

       private long mDuration;

       private long mCurrentPlayTime;

       private long mTotalTime;

       private Way mWay;

       private boolean mIsPanning;

       public PanningViewAttacher(ImageView imageView, long duration) {

              if (imageView == null) {

                     throw new IllegalArgumentException("imageView must not be null");

              }

              if (!hasDrawable(imageView)) {

                     throw new IllegalArgumentException("drawable must not be null");

              }

              mLinearInterpolator = new LinearInterpolator();

              mDuration = duration;

              mImageView = new WeakReference<ImageView>(imageView);

              mViewTreeObserver = imageView.getViewTreeObserver();

              mViewTreeObserver.addOnGlobalLayoutListener(this);

              setImageViewScaleTypeMatrix(imageView);

              mMatrix = imageView.getImageMatrix();

              if (mMatrix == null) {

                     mMatrix = new Matrix();

              }

              mIsPortrait = imageView.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;

              update();

       }

       /**

*

*/

       public void update() {

              mWay = null;

              mTotalTime = 0;

              mCurrentPlayTime = 0;

              getImageView().post(new Runnable() {

                     @Override
                     public void run() {

                           scale();

                           refreshDisplayRect();

                     }

              });

       }

       public boolean isPanning() {

              return mIsPanning;

       }

       /**
        *
        * scale and start to pan the image background
        */

       public void startPanning() {

              if (mIsPanning) {

                     return;

              }

              mIsPanning = true;

              final Runnable panningRunnable = new Runnable() {

                     @Override
                     public void run() {

                           animate_();

                     }

              };

              getImageView().post(panningRunnable);

       }

       /**
        *
        * stop current panning
        */

       public void stopPanning() {

              if (!mIsPanning) {

                     return;

              }

              mIsPanning = false;

              Log.d(TAG, "panning animation stopped by user");

              if (mCurrentAnimator != null) {

                     mCurrentAnimator.removeAllListeners();

                     mCurrentAnimator.cancel();

                     mCurrentAnimator = null;

              }

              mTotalTime += mCurrentPlayTime;

              Log.d(TAG, "mTotalTime : " + mTotalTime);

       }

       /**
        *
        * Clean-up the resources attached to this object. This needs to be called
        *
        * when the ImageView is no longer used. A good example is from
        *
        * {@link android.view.View#onDetachedFromWindow()} or from
        *
        * {@link android.app.Activity#onDestroy()}. This is automatically called if
        *
        * you are using {@link com.fourmob.panningview.PanningView}.
        */

       public final void cleanup() {

              if (null != mImageView) {

                     getImageView().getViewTreeObserver().removeGlobalOnLayoutListener(

                     this);

              }

              mViewTreeObserver = null;

              stopPanning();

              // Finally, clear ImageView

              mImageView = null;

       }

       public final ImageView getImageView() {

              ImageView imageView = null;

              if (null != mImageView) {

                     imageView = mImageView.get();

              }

              // If we don't have an ImageView, call cleanup()

              if (null == imageView) {

                     cleanup();

                     throw new IllegalStateException(

                                  "ImageView no longer exists. You should not use this PanningViewAttacher any more.");

              }

              return imageView;

       }

       private int getDrawableIntrinsicHeight() {

              return getImageView().getDrawable().getIntrinsicHeight();

       }

       private int getDrawableIntrinsicWidth() {

              return getImageView().getDrawable().getIntrinsicWidth();

       }

       private int getImageViewWidth() {

              return getImageView().getWidth();

       }

       private int getImageViewHeight() {

              return getImageView().getHeight();

       }

       /**
        *
        * Set's the ImageView's ScaleType to Matrix.
        */

       private static void setImageViewScaleTypeMatrix(ImageView imageView) {

              if (null != imageView && !(imageView instanceof PanningView)) {

                     imageView.setScaleType(ImageView.ScaleType.MATRIX);

              }

       }

       /**
        *
        * @return true if the ImageView exists, and it's Drawable exists
        */

       private static boolean hasDrawable(ImageView imageView) {

              return null != imageView && null != imageView.getDrawable();

       }

       @Override
       public void onGlobalLayout() {

              ImageView imageView = getImageView();

              if (null != imageView) {

                     final int top = imageView.getTop();

                     final int right = imageView.getRight();

                     final int bottom = imageView.getBottom();

                     final int left = imageView.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();

                           // Update values as something has changed

                           mIvTop = top;

                           mIvRight = right;

                           mIvBottom = bottom;

                           mIvLeft = left;

                     }

              }

       }

       private void animate_() {

              refreshDisplayRect();

              if (mWay == null) {

                     mWay = mIsPortrait ? Way.R2L : Way.B2T;

              }

              Log.d(TAG, "mWay : " + mWay);

              Log.d(TAG, "mDisplayRect : " + mDisplayRect);

              long remainingDuration = mDuration - mTotalTime;

              if (mIsPortrait) {

                     if (mWay == Way.R2L) {

                           animate(mDisplayRect.left, mDisplayRect.left

                           - (mDisplayRect.right - getImageViewWidth()),

                           remainingDuration);

                     } else {

                           animate(mDisplayRect.left, 0.0f, remainingDuration);

                     }

              } else {

                     if (mWay == Way.B2T) {

                           animate(mDisplayRect.top, mDisplayRect.top

                           - (mDisplayRect.bottom - getImageViewHeight()),

                           remainingDuration);

                     } else {

                           animate(mDisplayRect.top, 0.0f, remainingDuration);

                     }

              }

       }

       private void changeWay() {

              if (mWay == Way.R2L) {

                     mWay = Way.L2R;

              } else if (mWay == Way.L2R) {

                     mWay = Way.R2L;

              } else if (mWay == Way.T2B) {

                     mWay = Way.B2T;

              } else if (mWay == Way.B2T) {

                     mWay = Way.T2B;

              }

              mCurrentPlayTime = 0;

              mTotalTime = 0;

       }

       private void animate(float start, float end, long duration) {

              Log.d(TAG, "startPanning : " + start + " to " + end + ", in "

              + duration + "ms");

              mCurrentAnimator = ValueAnimator.ofFloat(start, end);

              mCurrentAnimator

              .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

                     @Override
                     public void onAnimationUpdate(ValueAnimator animation) {

                           float value = (Float) animation.getAnimatedValue();

                           mMatrix.reset();

                           applyScaleOnMatrix();

                           if (mIsPortrait) {

                                  mMatrix.postTranslate(value, 0);

                           } else {

                                  mMatrix.postTranslate(0, value);

                           }

                           refreshDisplayRect();

                           mCurrentPlayTime = animation.getCurrentPlayTime();

                           setCurrentImageMatrix();

                     }

              });

              mCurrentAnimator.addListener(new AnimatorListenerAdapter() {

                     @Override
                     public void onAnimationEnd(Animator animation) {

                           Log.d(TAG,

                           "animation has finished, startPanning in the other way");

                           changeWay();

                           animate_();

                     }

                     @Override
                     public void onAnimationCancel(Animator animation) {

                           Log.d(TAG, "panning animation canceled");

                     }

              });

              mCurrentAnimator.setDuration(duration);

              mCurrentAnimator.setInterpolator(mLinearInterpolator);

              mCurrentAnimator.start();

       }

       private void setCurrentImageMatrix() {

              getImageView().setImageMatrix(mMatrix);

              getImageView().invalidate();

              getImageView().requestLayout();

       }

       private void refreshDisplayRect() {

              mDisplayRect.set(0, 0, getDrawableIntrinsicWidth(),

              getDrawableIntrinsicHeight());

              mMatrix.mapRect(mDisplayRect);

       }

       private void scale() {

              mMatrix.reset();

              applyScaleOnMatrix();

              setCurrentImageMatrix();

       }

       private void applyScaleOnMatrix() {

              int drawableSize = mIsPortrait ? getDrawableIntrinsicHeight()

              : getDrawableIntrinsicWidth();

              int imageViewSize = mIsPortrait ? getImageViewHeight()

              : getImageViewWidth();

              float scaleFactor = (float) imageViewSize / (float) drawableSize;

              mMatrix.postScale(scaleFactor, scaleFactor);

       }

}


activity_main.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <com.iamvijayakumar.panningviewwith.PanningView
        android:id="@+id/panningView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/images1"
        custom:panningDurationInMs="10000" />

</RelativeLayout>


AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.iamvijayakumar.panningviewwith"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>



Download SourceCode

No comments:

Post a Comment

Check out this may be help you

Related Posts Plugin for WordPress, Blogger...