├── ic_launcher-web.png ├── res ├── drawable-hdpi │ ├── bg.png │ ├── p1.jpg │ ├── p2.jpg │ ├── p3.jpg │ ├── p4.jpg │ ├── charming.jpg │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ └── ic_launcher.png ├── drawable-xxhdpi │ └── ic_launcher.png ├── values-sw600dp │ └── dimens.xml ├── values │ ├── dimens.xml │ ├── strings.xml │ ├── styles.xml │ └── attrs.xml ├── values-sw720dp-land │ └── dimens.xml ├── values-v11 │ └── styles.xml ├── values-v14 │ └── styles.xml ├── layout │ ├── activity_next.xml │ └── activity_main.xml └── menu │ └── main.xml ├── libs └── android-support-v4.jar ├── README.md ├── gen └── com │ └── dk │ └── animation │ ├── BuildConfig.java │ └── R.java ├── .settings └── org.eclipse.jdt.core.prefs ├── .gitignore ├── src └── com │ └── dk │ └── animation │ ├── folding │ ├── Util.java │ ├── OnFoldListener.java │ ├── FoldingLayout.java │ └── BaseFoldingLayout.java │ ├── BaseEffect.java │ ├── demo │ ├── NextActivity.java │ └── MainActivity.java │ ├── ActivityAnimationTool.java │ ├── WaterEffect.java │ ├── FoldingEffect.java │ ├── water │ ├── DrawWaterWave.java │ └── DrawWaterWaveWithSina.java │ ├── SkewEffect.java │ ├── CloseEffect.java │ ├── TwisterEffect.java │ ├── SplitEffect.java │ └── BlurEffect.java ├── .classpath ├── project.properties ├── proguard-project.txt ├── .project └── AndroidManifest.xml /ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkmeteor/ActivityAnimationLib/HEAD/ic_launcher-web.png -------------------------------------------------------------------------------- /res/drawable-hdpi/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkmeteor/ActivityAnimationLib/HEAD/res/drawable-hdpi/bg.png -------------------------------------------------------------------------------- /res/drawable-hdpi/p1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkmeteor/ActivityAnimationLib/HEAD/res/drawable-hdpi/p1.jpg -------------------------------------------------------------------------------- /res/drawable-hdpi/p2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkmeteor/ActivityAnimationLib/HEAD/res/drawable-hdpi/p2.jpg -------------------------------------------------------------------------------- /res/drawable-hdpi/p3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkmeteor/ActivityAnimationLib/HEAD/res/drawable-hdpi/p3.jpg -------------------------------------------------------------------------------- /res/drawable-hdpi/p4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkmeteor/ActivityAnimationLib/HEAD/res/drawable-hdpi/p4.jpg -------------------------------------------------------------------------------- /libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkmeteor/ActivityAnimationLib/HEAD/libs/android-support-v4.jar -------------------------------------------------------------------------------- /res/drawable-hdpi/charming.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkmeteor/ActivityAnimationLib/HEAD/res/drawable-hdpi/charming.jpg -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkmeteor/ActivityAnimationLib/HEAD/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkmeteor/ActivityAnimationLib/HEAD/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkmeteor/ActivityAnimationLib/HEAD/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkmeteor/ActivityAnimationLib/HEAD/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Demo 2 | ![Examples list](http://dk-exp.com/wp-content/uploads/2014/07/water.gif) 3 | 4 | ![Examples list](http://dk-exp.com/wp-content/uploads/2014/07/folder.gif) -------------------------------------------------------------------------------- /gen/com/dk/animation/BuildConfig.java: -------------------------------------------------------------------------------- 1 | /** Automatically generated file. DO NOT MODIFY */ 2 | package com.dk.animation; 3 | 4 | public final class BuildConfig { 5 | public final static boolean DEBUG = true; 6 | } -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 3 | org.eclipse.jdt.core.compiler.compliance=1.6 4 | org.eclipse.jdt.core.compiler.source=1.6 5 | -------------------------------------------------------------------------------- /res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /res/values-sw720dp-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 128dp 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Android generated 2 | bin 3 | gen 4 | 5 | #Eclipse 6 | .project 7 | .classpath 8 | .settings 9 | 10 | #IntelliJ IDEA 11 | .idea 12 | *.iml 13 | *.ipr 14 | *.iws 15 | out 16 | 17 | #Maven 18 | target 19 | release.properties 20 | pom.xml.* 21 | 22 | #Ant 23 | build.xml 24 | local.properties 25 | proguard.cfg 26 | 27 | #OSX 28 | .DS_Store 29 | -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/com/dk/animation/folding/Util.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation.folding; 2 | 3 | import android.os.Build; 4 | 5 | public class Util { 6 | 7 | static final boolean IS_JBMR2 = Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR2; 8 | static final boolean IS_ISC = Build.VERSION.SDK_INT == Build.VERSION_CODES.ICE_CREAM_SANDWICH; 9 | static final boolean IS_GINGERBREAD_MR1 = Build.VERSION.SDK_INT == Build.VERSION_CODES.GINGERBREAD_MR1; 10 | } 11 | -------------------------------------------------------------------------------- /src/com/dk/animation/BaseEffect.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation; 2 | 3 | import android.app.Activity; 4 | 5 | public abstract class BaseEffect { 6 | public abstract void prepareAnimation(final Activity destActivity); 7 | 8 | public abstract void prepare(Activity currActivity); 9 | 10 | public abstract void clean(Activity activity); 11 | 12 | public abstract void cancel(); 13 | 14 | public abstract void animate(final Activity destActivity, final int duration); 15 | } 16 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /res/layout/activity_next.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ActivityAnimationLib 5 | Settings 6 | Hello world! 7 | blur 8 | split 9 | close 10 | twister 11 | folding 12 | skew 13 | water 14 | 15 | -------------------------------------------------------------------------------- /src/com/dk/animation/demo/NextActivity.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation.demo; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | import com.dk.animation.ActivityAnimationTool; 7 | import com.dk.animation.R; 8 | 9 | public class NextActivity extends Activity { 10 | 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | ActivityAnimationTool.prepareAnimation(this); 15 | setContentView(R.layout.activity_next); 16 | ActivityAnimationTool.animate(this, 1000); 17 | } 18 | 19 | @Override 20 | protected void onStop() { 21 | ActivityAnimationTool.cancel(this); 22 | super.onStop(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | ActivityAnimationLib 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/com/dk/animation/folding/OnFoldListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.dk.animation.folding; 18 | 19 | /** 20 | * This interface listens for when the folding layout begins folding (enters 21 | * a folded state from a completely unfolded state), or ends folding (enters a 22 | * completely unfolded state from a folded state). 23 | */ 24 | public interface OnFoldListener { 25 | public void onStartFold(); 26 | public void onEndFold(); 27 | } 28 | -------------------------------------------------------------------------------- /src/com/dk/animation/ActivityAnimationTool.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.view.animation.DecelerateInterpolator; 6 | 7 | public class ActivityAnimationTool { 8 | private static BaseEffect mEffect; 9 | 10 | public static void init(BaseEffect effect) { 11 | mEffect = effect; 12 | } 13 | 14 | public static void startActivity(Activity currActivity, Intent intent) { 15 | 16 | // Preparing the bitmaps that we need to show 17 | mEffect.prepare(currActivity); 18 | currActivity.startActivity(intent); 19 | currActivity.overridePendingTransition(0, 0); 20 | } 21 | 22 | public static void animate(final Activity destActivity, final int duration) { 23 | mEffect.animate(destActivity, duration); 24 | } 25 | 26 | public static void cancel(final Activity destActivity) { 27 | mEffect.cancel(); 28 | mEffect.clean(destActivity); 29 | } 30 | 31 | public static void prepareAnimation(final Activity destActivity) { 32 | mEffect.prepareAnimation(destActivity); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 14 | 19 | 24 | 25 | 30 | 31 | 36 | -------------------------------------------------------------------------------- /src/com/dk/animation/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation.demo; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.Menu; 7 | import android.view.MenuItem; 8 | import android.view.View; 9 | 10 | import com.dk.animation.ActivityAnimationTool; 11 | import com.dk.animation.BlurEffect; 12 | import com.dk.animation.CloseEffect; 13 | import com.dk.animation.FoldingEffect; 14 | import com.dk.animation.R; 15 | import com.dk.animation.SkewEffect; 16 | import com.dk.animation.SplitEffect; 17 | import com.dk.animation.TwisterEffect; 18 | import com.dk.animation.WaterEffect; 19 | 20 | public class MainActivity extends Activity { 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_main); 26 | 27 | ActivityAnimationTool.init(new WaterEffect()); 28 | findViewById(R.id.iv).setOnClickListener(new View.OnClickListener() { 29 | 30 | @Override 31 | public void onClick(View v) { 32 | ActivityAnimationTool.startActivity(MainActivity.this, new Intent(MainActivity.this, NextActivity.class)); 33 | } 34 | }); 35 | } 36 | 37 | @Override 38 | public boolean onCreateOptionsMenu(Menu menu) { 39 | getMenuInflater().inflate(R.menu.main, menu); 40 | return true; 41 | } 42 | 43 | @Override 44 | public boolean onOptionsItemSelected(MenuItem item) { 45 | switch (item.getItemId()) { 46 | case R.id.action_blur: 47 | ActivityAnimationTool.init(new BlurEffect()); 48 | break; 49 | case R.id.action_close: 50 | ActivityAnimationTool.init(new CloseEffect()); 51 | break; 52 | case R.id.action_split: 53 | ActivityAnimationTool.init(new SplitEffect()); 54 | break; 55 | // case R.id.action_twister: 56 | // ActivityAnimationTool.init(new TwisterEffect()); 57 | // break; 58 | case R.id.action_folding: 59 | ActivityAnimationTool.init(new FoldingEffect()); 60 | break; 61 | case R.id.action_skew: 62 | ActivityAnimationTool.init(new SkewEffect()); 63 | break; 64 | case R.id.action_water: 65 | ActivityAnimationTool.init(new WaterEffect()); 66 | break; 67 | } 68 | return super.onOptionsItemSelected(item); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/com/dk/animation/WaterEffect.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Activity; 5 | import android.graphics.Bitmap; 6 | import android.graphics.PixelFormat; 7 | import android.os.Handler; 8 | import android.os.Message; 9 | import android.view.Gravity; 10 | import android.view.View; 11 | import android.view.WindowManager; 12 | 13 | import com.dk.animation.water.DrawWaterWaveWithSina; 14 | 15 | public class WaterEffect extends BaseEffect { 16 | private Bitmap mBitmap = null; 17 | private DrawWaterWaveWithSina mTopImage; 18 | private int top; 19 | 20 | public void prepareAnimation(final Activity destActivity) { 21 | mTopImage = createImageView(destActivity, mBitmap); 22 | } 23 | 24 | public void prepare(Activity currActivity) { 25 | View root = currActivity.getWindow().getDecorView().findViewById(android.R.id.content); 26 | top = root.getTop(); 27 | root.setDrawingCacheEnabled(true); 28 | mBitmap = root.getDrawingCache(); 29 | } 30 | 31 | public void cancel() { 32 | } 33 | 34 | public void clean(Activity activity) { 35 | if (mTopImage != null) { 36 | mTopImage.setLayerType(View.LAYER_TYPE_NONE, null); 37 | try { 38 | // If we use the regular removeView() we'll get a small UI glitch 39 | activity.getWindowManager().removeViewImmediate(mTopImage); 40 | } catch (Exception ignored) { 41 | } 42 | } 43 | mBitmap = null; 44 | } 45 | 46 | private DrawWaterWaveWithSina createImageView(Activity destActivity, Bitmap bmp) { 47 | DrawWaterWaveWithSina imageView = new DrawWaterWaveWithSina(destActivity, bmp); 48 | WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams(); 49 | windowParams.gravity = Gravity.TOP; 50 | windowParams.x = 0; 51 | windowParams.y = top; 52 | windowParams.height = bmp.getHeight(); 53 | windowParams.width = bmp.getWidth(); 54 | windowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 55 | windowParams.format = PixelFormat.TRANSLUCENT; 56 | windowParams.windowAnimations = 0; 57 | destActivity.getWindowManager().addView(imageView, windowParams); 58 | 59 | return imageView; 60 | } 61 | 62 | @SuppressLint("HandlerLeak") 63 | public void animate(final Activity destActivity, final int duration) { 64 | 65 | new Handler().post(new Runnable() { 66 | 67 | @Override 68 | public void run() { 69 | 70 | final Handler callBack = new Handler() { 71 | 72 | @Override 73 | public void handleMessage(Message msg) { 74 | switch (msg.what) { 75 | case 101: 76 | mTopImage.start(mBitmap.getWidth() / 2, mBitmap.getHeight() / 2); 77 | break; 78 | case 102: 79 | clean(destActivity); 80 | break; 81 | } 82 | } 83 | }; 84 | 85 | Thread animationThread = new Thread(new Runnable() { 86 | 87 | @Override 88 | public void run() { 89 | 90 | callBack.sendEmptyMessage(101); 91 | // 92 | // callBack.sendEmptyMessage(102); 93 | } 94 | }); 95 | 96 | animationThread.start(); 97 | 98 | } 99 | }); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/com/dk/animation/FoldingEffect.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation; 2 | 3 | import android.animation.Animator; 4 | import android.animation.Animator.AnimatorListener; 5 | import android.animation.ObjectAnimator; 6 | import android.animation.ValueAnimator; 7 | import android.app.Activity; 8 | import android.graphics.Bitmap; 9 | import android.graphics.PixelFormat; 10 | import android.os.Handler; 11 | import android.view.Gravity; 12 | import android.view.View; 13 | import android.view.WindowManager; 14 | import android.view.animation.AccelerateInterpolator; 15 | import android.widget.ImageView; 16 | 17 | import com.dk.animation.folding.FoldingLayout; 18 | 19 | public class FoldingEffect extends BaseEffect { 20 | 21 | public Bitmap mBitmap = null; 22 | private ImageView mTopImage; 23 | private FoldingLayout mLayout; 24 | private int top; 25 | private float t = 0; 26 | 27 | public void prepareAnimation(final Activity destActivity) { 28 | mTopImage = createImageView(destActivity, mBitmap); 29 | } 30 | 31 | public void prepare(Activity currActivity) { 32 | // Get the content of the activity and put in a bitmap 33 | View root = currActivity.getWindow().getDecorView().findViewById(android.R.id.content); 34 | root.setDrawingCacheEnabled(true); 35 | mBitmap = root.getDrawingCache(); 36 | top = root.getTop(); 37 | 38 | } 39 | 40 | public void cancel() { 41 | } 42 | 43 | public void clean(Activity activity) { 44 | 45 | if (mLayout != null) { 46 | mLayout.setLayerType(View.LAYER_TYPE_NONE, null); 47 | try { 48 | activity.getWindowManager().removeViewImmediate(mLayout); 49 | } catch (Exception ignored) { 50 | } 51 | } 52 | 53 | mBitmap = null; 54 | } 55 | 56 | private ImageView createImageView(Activity destActivity, Bitmap bmp) { 57 | mLayout = new FoldingLayout(destActivity); 58 | ImageView imageView = new ImageView(destActivity); 59 | 60 | mLayout.addView(imageView); 61 | imageView.setImageBitmap(bmp); 62 | 63 | WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams(); 64 | windowParams.gravity = Gravity.TOP; 65 | windowParams.x = 0; 66 | windowParams.y = top; 67 | windowParams.height = bmp.getHeight(); 68 | windowParams.width = bmp.getWidth(); 69 | windowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 70 | windowParams.format = PixelFormat.TRANSLUCENT; 71 | windowParams.windowAnimations = 0; 72 | destActivity.getWindowManager().addView(mLayout, windowParams); 73 | 74 | return imageView; 75 | } 76 | 77 | public void animate(final Activity destActivity, final int duration) { 78 | 79 | new Handler().post(new Runnable() { 80 | 81 | @Override 82 | public void run() { 83 | mLayout.setNumberOfFolds(8); 84 | float foldFactor = mLayout.getFoldFactor(); 85 | 86 | ObjectAnimator animator = ObjectAnimator.ofFloat(mLayout, "foldFactor", foldFactor, 1); 87 | animator.setRepeatMode(ValueAnimator.RESTART); 88 | animator.setRepeatCount(0); 89 | animator.setDuration(500); 90 | animator.setInterpolator(new AccelerateInterpolator()); 91 | animator.start(); 92 | 93 | animator.addListener(new AnimatorListener() { 94 | 95 | @Override 96 | public void onAnimationStart(Animator animation) { 97 | // TODO Auto-generated method stub 98 | 99 | } 100 | 101 | @Override 102 | public void onAnimationRepeat(Animator animation) { 103 | // TODO Auto-generated method stub 104 | 105 | } 106 | 107 | @Override 108 | public void onAnimationEnd(Animator animation) { 109 | clean(destActivity); 110 | } 111 | 112 | @Override 113 | public void onAnimationCancel(Animator animation) { 114 | // TODO Auto-generated method stub 115 | 116 | } 117 | }); 118 | } 119 | }); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/com/dk/animation/water/DrawWaterWave.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation.water; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.view.MotionEvent; 7 | import android.view.View; 8 | 9 | public class DrawWaterWave extends View implements Runnable { 10 | boolean isRunning = false; 11 | 12 | int BACKWIDTH; 13 | 14 | int BACKHEIGHT; 15 | 16 | short[] buf2; 17 | 18 | short[] buf1; 19 | 20 | int[] Bitmap2; 21 | 22 | int[] Bitmap1; 23 | 24 | public DrawWaterWave(Context context, Bitmap bmp) { 25 | super(context); 26 | 27 | Bitmap image = bmp; 28 | BACKWIDTH = image.getWidth(); 29 | BACKHEIGHT = image.getHeight(); 30 | 31 | buf2 = new short[BACKWIDTH * BACKHEIGHT]; 32 | buf1 = new short[BACKWIDTH * BACKHEIGHT]; 33 | Bitmap2 = new int[BACKWIDTH * BACKHEIGHT]; 34 | Bitmap1 = new int[BACKWIDTH * BACKHEIGHT]; 35 | 36 | image.getPixels(Bitmap1, 0, BACKWIDTH, 0, 0, BACKWIDTH, BACKHEIGHT); 37 | 38 | start(); 39 | } 40 | 41 | void dropStone(int x, int y, int stonesize, int stoneweight) { 42 | if ((x + stonesize) > BACKWIDTH || (y + stonesize) > BACKHEIGHT || (x - stonesize) < 0 || (y - stonesize) < 0) 43 | return; 44 | 45 | for (int posx = x - stonesize; posx < x + stonesize; posx++) 46 | for (int posy = y - stonesize; posy < y + stonesize; posy++) 47 | if ((posx - x) * (posx - x) + (posy - y) * (posy - y) < stonesize * stonesize) 48 | buf1[BACKWIDTH * posy + posx] = (short)-stoneweight; 49 | } 50 | 51 | protected void onDraw(Canvas canvas) { 52 | canvas.drawColor(0x00000000); 53 | canvas.drawBitmap(Bitmap2, 0, BACKWIDTH, 0, 0, BACKWIDTH, BACKHEIGHT, false, null); 54 | } 55 | 56 | public void start() { 57 | isRunning = true; 58 | Thread t = new Thread(this); 59 | t.start(); 60 | } 61 | 62 | public void key() { 63 | dropStone(BACKWIDTH / 2, BACKHEIGHT / 2, 10, 50); 64 | } 65 | 66 | public void stop() { 67 | isRunning = false; 68 | } 69 | 70 | public void run() { 71 | 72 | while (isRunning) { 73 | try { 74 | Thread.sleep(10); 75 | } catch (Exception e) { 76 | e.printStackTrace(); 77 | } 78 | ; 79 | RippleSpread(); 80 | render(); 81 | postInvalidate(); 82 | } 83 | } 84 | 85 | void RippleSpread() { 86 | for (int i = BACKWIDTH; i < BACKWIDTH * BACKHEIGHT - BACKWIDTH; i++) { 87 | 88 | buf2[i] = (short)(((buf1[i - 1] + buf1[i + 1] + buf1[i - BACKWIDTH] + buf1[i + BACKWIDTH]) >> 1) - buf2[i]); 89 | 90 | buf2[i] -= buf2[i] >> 5; 91 | } 92 | 93 | short[] ptmp = buf1; 94 | buf1 = buf2; 95 | buf2 = ptmp; 96 | } 97 | 98 | void render() { 99 | int xoff, yoff; 100 | int k = BACKWIDTH; 101 | for (int i = 1; i < BACKHEIGHT - 1; i++) { 102 | for (int j = 0; j < BACKWIDTH; j++) { 103 | xoff = buf1[k - 1] - buf1[k + 1]; 104 | yoff = buf1[k - BACKWIDTH] - buf1[k + BACKWIDTH]; 105 | 106 | if ((i + yoff) < 0) { 107 | k++; 108 | continue; 109 | } 110 | if ((i + yoff) > BACKHEIGHT) { 111 | k++; 112 | continue; 113 | } 114 | if ((j + xoff) < 0) { 115 | k++; 116 | continue; 117 | } 118 | if ((j + xoff) > BACKWIDTH) { 119 | k++; 120 | continue; 121 | } 122 | 123 | int pos1, pos2; 124 | pos1 = BACKWIDTH * (i + yoff) + (j + xoff); 125 | pos2 = BACKWIDTH * i + j; 126 | Bitmap2[pos2++] = Bitmap1[pos1++]; 127 | k++; 128 | } 129 | } 130 | } 131 | 132 | 133 | @Override 134 | public boolean onTouchEvent(MotionEvent event) { 135 | 136 | if (event.getAction() == MotionEvent.ACTION_DOWN && !isRunning) { 137 | dropStone((int)event.getX(), (int)event.getY(), 10, 50); 138 | } 139 | 140 | return super.onTouchEvent(event); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/com/dk/animation/SkewEffect.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Camera; 7 | import android.graphics.Canvas; 8 | import android.graphics.Matrix; 9 | import android.graphics.Paint; 10 | import android.graphics.PixelFormat; 11 | import android.os.Handler; 12 | import android.os.Message; 13 | import android.view.Gravity; 14 | import android.view.View; 15 | import android.view.WindowManager; 16 | import android.widget.ImageView; 17 | 18 | public class SkewEffect extends BaseEffect { 19 | public Bitmap mBitmap = null; 20 | private ImageView mTopImage; 21 | private int top; 22 | private float t = 0; 23 | 24 | public void prepareAnimation(final Activity destActivity) { 25 | mTopImage = createImageView(destActivity, mBitmap); 26 | } 27 | 28 | public void prepare(Activity currActivity) { 29 | // Get the content of the activity and put in a bitmap 30 | View root = currActivity.getWindow().getDecorView().findViewById(android.R.id.content); 31 | root.setDrawingCacheEnabled(true); 32 | mBitmap = root.getDrawingCache(); 33 | top = root.getTop(); 34 | 35 | } 36 | 37 | public void cancel() { 38 | } 39 | 40 | public void clean(Activity activity) { 41 | 42 | if (mTopImage != null) { 43 | mTopImage.setLayerType(View.LAYER_TYPE_NONE, null); 44 | try { 45 | activity.getWindowManager().removeViewImmediate(mTopImage); 46 | } catch (Exception ignored) { 47 | } 48 | } 49 | 50 | mBitmap = null; 51 | } 52 | 53 | private ImageView createImageView(Activity destActivity, Bitmap bmp) { 54 | MyImageView imageView = new MyImageView(destActivity); 55 | imageView.setImageBitmap(bmp); 56 | 57 | WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams(); 58 | windowParams.gravity = Gravity.TOP; 59 | windowParams.x = 0; 60 | windowParams.y = top; 61 | windowParams.height = bmp.getHeight(); 62 | windowParams.width = bmp.getWidth(); 63 | windowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 64 | windowParams.format = PixelFormat.TRANSLUCENT; 65 | windowParams.windowAnimations = 0; 66 | destActivity.getWindowManager().addView(imageView, windowParams); 67 | 68 | return imageView; 69 | } 70 | 71 | public void animate(final Activity destActivity, final int duration) { 72 | 73 | new Handler().post(new Runnable() { 74 | 75 | @Override 76 | public void run() { 77 | 78 | final Handler callBack = new Handler() { 79 | 80 | @Override 81 | public void handleMessage(Message msg) { 82 | switch (msg.what) { 83 | case 101: 84 | mTopImage.invalidate(); 85 | break; 86 | case 102: 87 | clean(destActivity); 88 | break; 89 | } 90 | } 91 | }; 92 | 93 | Thread animationThread = new Thread(new Runnable() { 94 | 95 | @Override 96 | public void run() { 97 | t = 0; 98 | while (t < 1) { 99 | t += 0.08; 100 | callBack.sendEmptyMessage(101); 101 | 102 | try { 103 | Thread.sleep(20); 104 | } catch (InterruptedException e) { 105 | e.printStackTrace(); 106 | } 107 | } 108 | 109 | callBack.sendEmptyMessage(102); 110 | 111 | } 112 | }); 113 | 114 | animationThread.start(); 115 | 116 | } 117 | }); 118 | } 119 | 120 | private class MyImageView extends ImageView { 121 | private Matrix mMatrix; 122 | private Camera mCamera = new Camera(); 123 | private Paint mPaint = new Paint(); 124 | 125 | public MyImageView(Context context) { 126 | super(context); 127 | } 128 | 129 | @Override 130 | protected void onDraw(Canvas canvas) { 131 | if (mMatrix != null) 132 | mMatrix.reset(); 133 | mMatrix = SkewEffect.this.getMatrix(canvas.getMatrix(), t, getWidth(), getHeight()); 134 | mPaint.setAntiAlias(true); 135 | canvas.drawBitmap(mBitmap, mMatrix, mPaint); 136 | } 137 | } 138 | 139 | /** 140 | * t should be 0~1; 141 | * 142 | * @param t 143 | * @param w 144 | * @param h 145 | * @return 146 | */ 147 | private Matrix getMatrix(Matrix matrix, float t, int w, int h) { 148 | matrix.setSkew(t, t); 149 | return matrix; 150 | 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /gen/com/dk/animation/R.java: -------------------------------------------------------------------------------- 1 | /* AUTO-GENERATED FILE. DO NOT MODIFY. 2 | * 3 | * This class was automatically generated by the 4 | * aapt tool from the resource data it found. It 5 | * should not be modified by hand. 6 | */ 7 | 8 | package com.dk.animation; 9 | 10 | public final class R { 11 | public static final class attr { 12 | /**

Must be an integer value, such as "100". 13 |

This may also be a reference to a resource (in the form 14 | "@[package:]type:name") or 15 | theme attribute (in the form 16 | "?[package:][type:]name") 17 | containing a value of this type. 18 | */ 19 | public static final int foldNumber=0x7f010000; 20 | } 21 | public static final class dimen { 22 | /** Default screen margins, per the Android Design guidelines. 23 | 24 | Customize dimensions originally defined in res/values/dimens.xml (such as 25 | screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. 26 | 27 | */ 28 | public static final int activity_horizontal_margin=0x7f040000; 29 | public static final int activity_vertical_margin=0x7f040001; 30 | } 31 | public static final class drawable { 32 | public static final int bg=0x7f020000; 33 | public static final int charming=0x7f020001; 34 | public static final int ic_launcher=0x7f020002; 35 | public static final int p1=0x7f020003; 36 | public static final int p2=0x7f020004; 37 | public static final int p3=0x7f020005; 38 | public static final int p4=0x7f020006; 39 | } 40 | public static final class id { 41 | public static final int action_blur=0x7f080001; 42 | public static final int action_close=0x7f080002; 43 | public static final int action_folding=0x7f080004; 44 | public static final int action_skew=0x7f080005; 45 | public static final int action_split=0x7f080003; 46 | public static final int action_water=0x7f080006; 47 | public static final int iv=0x7f080000; 48 | } 49 | public static final class layout { 50 | public static final int activity_main=0x7f030000; 51 | public static final int activity_next=0x7f030001; 52 | } 53 | public static final class menu { 54 | public static final int main=0x7f070000; 55 | } 56 | public static final class string { 57 | public static final int action_settings=0x7f050001; 58 | public static final int app_name=0x7f050000; 59 | public static final int effect_blur=0x7f050003; 60 | public static final int effect_close=0x7f050005; 61 | public static final int effect_folding=0x7f050007; 62 | public static final int effect_skew=0x7f050008; 63 | public static final int effect_split=0x7f050004; 64 | public static final int effect_twister=0x7f050006; 65 | public static final int effect_water=0x7f050009; 66 | public static final int hello_world=0x7f050002; 67 | } 68 | public static final class style { 69 | /** 70 | Base application theme, dependent on API level. This theme is replaced 71 | by AppBaseTheme from res/values-vXX/styles.xml on newer devices. 72 | 73 | 74 | Theme customizations available in newer API levels can go in 75 | res/values-vXX/styles.xml, while customizations related to 76 | backward-compatibility can go here. 77 | 78 | 79 | Base application theme for API 11+. This theme completely replaces 80 | AppBaseTheme from res/values/styles.xml on API 11+ devices. 81 | 82 | API 11 theme customizations can go here. 83 | 84 | Base application theme for API 14+. This theme completely replaces 85 | AppBaseTheme from BOTH res/values/styles.xml and 86 | res/values-v11/styles.xml on API 14+ devices. 87 | 88 | API 14 theme customizations can go here. 89 | */ 90 | public static final int AppBaseTheme=0x7f060000; 91 | /** Application theme. 92 | */ 93 | public static final int AppTheme=0x7f060001; 94 | } 95 | public static final class styleable { 96 | /** Attributes that can be used with a FoldingMenu. 97 |

Includes the following attributes:

98 | 99 | 100 | 101 | 102 | 103 |
AttributeDescription
{@link #FoldingMenu_foldNumber com.dk.animation:foldNumber}
104 | @see #FoldingMenu_foldNumber 105 | */ 106 | public static final int[] FoldingMenu = { 107 | 0x7f010000 108 | }; 109 | /** 110 |

This symbol is the offset where the {@link com.dk.animation.R.attr#foldNumber} 111 | attribute's value can be found in the {@link #FoldingMenu} array. 112 | 113 | 114 |

Must be an integer value, such as "100". 115 |

This may also be a reference to a resource (in the form 116 | "@[package:]type:name") or 117 | theme attribute (in the form 118 | "?[package:][type:]name") 119 | containing a value of this type. 120 | @attr name com.dk.animation:foldNumber 121 | */ 122 | public static final int FoldingMenu_foldNumber = 0; 123 | }; 124 | } 125 | -------------------------------------------------------------------------------- /src/com/dk/animation/CloseEffect.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Canvas; 7 | import android.graphics.Matrix; 8 | import android.graphics.Paint; 9 | import android.graphics.PixelFormat; 10 | import android.os.Handler; 11 | import android.os.Message; 12 | import android.view.Gravity; 13 | import android.view.View; 14 | import android.view.WindowManager; 15 | import android.widget.ImageView; 16 | 17 | public class CloseEffect extends BaseEffect { 18 | public Bitmap mBitmap = null; 19 | private ImageView mTopImage; 20 | private int top; 21 | private float t = 0; 22 | 23 | public void prepareAnimation(final Activity destActivity) { 24 | mTopImage = createImageView(destActivity, mBitmap); 25 | } 26 | 27 | public void prepare(Activity currActivity) { 28 | // Get the content of the activity and put in a bitmap 29 | View root = currActivity.getWindow().getDecorView().findViewById(android.R.id.content); 30 | root.setDrawingCacheEnabled(true); 31 | mBitmap = root.getDrawingCache(); 32 | top = root.getTop(); 33 | 34 | } 35 | 36 | public void cancel() { 37 | 38 | } 39 | 40 | public void clean(Activity activity) { 41 | 42 | if (mTopImage != null) { 43 | mTopImage.setLayerType(View.LAYER_TYPE_NONE, null); 44 | try { 45 | activity.getWindowManager().removeViewImmediate(mTopImage); 46 | } catch (Exception ignored) { 47 | } 48 | } 49 | 50 | mBitmap = null; 51 | } 52 | 53 | private ImageView createImageView(Activity destActivity, Bitmap bmp) { 54 | MyImageView imageView = new MyImageView(destActivity); 55 | imageView.setImageBitmap(bmp); 56 | 57 | WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams(); 58 | windowParams.gravity = Gravity.TOP; 59 | windowParams.x = 0; 60 | windowParams.y = top; 61 | windowParams.height = bmp.getHeight(); 62 | windowParams.width = bmp.getWidth(); 63 | windowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 64 | windowParams.format = PixelFormat.TRANSLUCENT; 65 | windowParams.windowAnimations = 0; 66 | destActivity.getWindowManager().addView(imageView, windowParams); 67 | 68 | return imageView; 69 | } 70 | 71 | 72 | public void animate(final Activity destActivity, final int duration) { 73 | 74 | //make sure it is run in main thread 75 | new Handler().post(new Runnable() { 76 | 77 | @Override 78 | public void run() { 79 | //callback UI thread 80 | final Handler callBack = new Handler() { 81 | 82 | @Override 83 | public void handleMessage(Message msg) { 84 | switch (msg.what) { 85 | case 101: 86 | mTopImage.invalidate(); 87 | break; 88 | case 102: 89 | clean(destActivity); 90 | break; 91 | } 92 | } 93 | }; 94 | 95 | Thread animationThread = new Thread(new Runnable() { 96 | 97 | @Override 98 | public void run() { 99 | while (t < 1) { 100 | t += 0.08; 101 | callBack.sendEmptyMessage(101); 102 | 103 | try { 104 | Thread.sleep(20); 105 | } catch (InterruptedException e) { 106 | e.printStackTrace(); 107 | } 108 | } 109 | 110 | callBack.sendEmptyMessage(102); 111 | } 112 | }); 113 | 114 | animationThread.start(); 115 | 116 | } 117 | }); 118 | } 119 | 120 | private class MyImageView extends ImageView { 121 | private Matrix mMatrix; 122 | private Paint mPaint = new Paint(); 123 | 124 | public MyImageView(Context context) { 125 | super(context); 126 | } 127 | 128 | @Override 129 | protected void onDraw(Canvas canvas) { 130 | if (mMatrix != null) 131 | mMatrix.reset(); 132 | mMatrix = CloseEffect.this.getMatrix(canvas.getMatrix(), t, getWidth(), getHeight()); 133 | canvas.drawBitmap(mBitmap, mMatrix, mPaint); 134 | 135 | } 136 | 137 | } 138 | 139 | /** 140 | * t should be 0~1; 141 | * 142 | * @param t 143 | * @param w 144 | * @param h 145 | * @return 146 | */ 147 | private Matrix getMatrix(Matrix matrix, float t, int w, int h) { 148 | float[] src = new float[8]; 149 | float[] dst = new float[8]; 150 | 151 | src[0] = 0; 152 | src[1] = 0; 153 | src[2] = w; 154 | src[3] = 0; 155 | src[4] = 0; 156 | src[5] = h; 157 | src[6] = w; 158 | src[7] = h; 159 | 160 | dst[0] = 0; 161 | dst[1] = 0.5f * h * t; 162 | dst[2] = w; 163 | dst[3] = 0.5f * h * t; 164 | dst[4] = 0; 165 | dst[5] = h - 0.5f * h * t; 166 | dst[6] = w; 167 | dst[7] = h - 0.5f * h * t; 168 | 169 | matrix.setPolyToPoly(src, 0, dst, 0, 4); 170 | return matrix; 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/com/dk/animation/TwisterEffect.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Camera; 7 | import android.graphics.Canvas; 8 | import android.graphics.Matrix; 9 | import android.graphics.Paint; 10 | import android.graphics.PixelFormat; 11 | import android.os.Handler; 12 | import android.os.Message; 13 | import android.view.Gravity; 14 | import android.view.View; 15 | import android.view.WindowManager; 16 | import android.widget.ImageView; 17 | 18 | public class TwisterEffect extends BaseEffect{ 19 | public Bitmap mBitmap = null; 20 | private ImageView mTopImage; 21 | private int top; 22 | private float t = 0; 23 | 24 | public void prepareAnimation(final Activity destActivity) { 25 | mTopImage = createImageView(destActivity, mBitmap); 26 | } 27 | 28 | public void prepare(Activity currActivity) { 29 | // Get the content of the activity and put in a bitmap 30 | View root = currActivity.getWindow().getDecorView().findViewById(android.R.id.content); 31 | root.setDrawingCacheEnabled(true); 32 | mBitmap = root.getDrawingCache(); 33 | top = root.getTop(); 34 | 35 | } 36 | 37 | public void cancel() { 38 | } 39 | 40 | public void clean(Activity activity) { 41 | 42 | if (mTopImage != null) { 43 | mTopImage.setLayerType(View.LAYER_TYPE_NONE, null); 44 | try { 45 | activity.getWindowManager().removeViewImmediate(mTopImage); 46 | } catch (Exception ignored) { 47 | } 48 | } 49 | 50 | mBitmap = null; 51 | } 52 | 53 | private ImageView createImageView(Activity destActivity, Bitmap bmp) { 54 | MyImageView imageView = new MyImageView(destActivity); 55 | imageView.setImageBitmap(bmp); 56 | 57 | WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams(); 58 | windowParams.gravity = Gravity.TOP; 59 | windowParams.x = 0; 60 | windowParams.y = top; 61 | windowParams.height = bmp.getHeight(); 62 | windowParams.width = bmp.getWidth(); 63 | windowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 64 | windowParams.format = PixelFormat.TRANSLUCENT; 65 | windowParams.windowAnimations = 0; 66 | destActivity.getWindowManager().addView(imageView, windowParams); 67 | 68 | return imageView; 69 | } 70 | 71 | public void animate(final Activity destActivity, final int duration) { 72 | 73 | new Handler().post(new Runnable() { 74 | 75 | @Override 76 | public void run() { 77 | 78 | final Handler callBack = new Handler() { 79 | 80 | @Override 81 | public void handleMessage(Message msg) { 82 | switch (msg.what) { 83 | case 101: 84 | mTopImage.invalidate(); 85 | break; 86 | case 102: 87 | clean(destActivity); 88 | break; 89 | } 90 | } 91 | }; 92 | 93 | Thread animationThread = new Thread(new Runnable() { 94 | 95 | @Override 96 | public void run() { 97 | while (t < 1) { 98 | t += 0.08; 99 | callBack.sendEmptyMessage(101); 100 | 101 | try { 102 | Thread.sleep(20); 103 | } catch (InterruptedException e) { 104 | e.printStackTrace(); 105 | } 106 | } 107 | 108 | callBack.sendEmptyMessage(102); 109 | } 110 | }); 111 | 112 | animationThread.start(); 113 | 114 | } 115 | }); 116 | } 117 | 118 | private class MyImageView extends ImageView { 119 | private Matrix mMatrix; 120 | private Camera mCamera = new Camera(); 121 | 122 | public MyImageView(Context context) { 123 | super(context); 124 | } 125 | 126 | @Override 127 | protected void onDraw(Canvas canvas) { 128 | if (mMatrix != null) 129 | mMatrix.reset(); 130 | mMatrix = TwisterEffect.this.getMatrix(canvas.getMatrix(), t, getWidth(), getHeight()); 131 | 132 | canvas.drawBitmap(mBitmap, mMatrix, new Paint()); 133 | } 134 | } 135 | 136 | /** 137 | * t should be 0~1; 138 | * 139 | * @param t 140 | * @param w 141 | * @param h 142 | * @return 143 | */ 144 | private Matrix getMatrix(Matrix matrix, float t, int w, int h) { 145 | float[] src = new float[8]; 146 | float[] dst = new float[8]; 147 | 148 | src[0] = 0; 149 | src[1] = 0; 150 | src[2] = w; 151 | src[3] = 0; 152 | src[4] = 0; 153 | src[5] = h; 154 | src[6] = w; 155 | src[7] = h; 156 | 157 | dst[0] = 0; 158 | dst[1] = 0.5f * h * t; 159 | dst[2] = w; 160 | dst[3] = 0.5f * h * t; 161 | dst[4] = 0; 162 | dst[5] = h - 0.5f * h * t; 163 | dst[6] = w; 164 | dst[7] = h - 0.5f * h * t; 165 | 166 | matrix.setPolyToPoly(src, 0, dst, 0, 4); 167 | 168 | for (int i = 0; i < 8; i++) { 169 | System.out.print(" " + dst[i]); 170 | } 171 | System.out.println(); 172 | return matrix; 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/com/dk/animation/water/DrawWaterWaveWithSina.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation.water; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Paint; 6 | import android.widget.ImageView; 7 | 8 | public class DrawWaterWaveWithSina extends ImageView implements Runnable { 9 | boolean isRunning = false; 10 | 11 | private final static double TWO_PI = Math.PI * 2; 12 | private int width; 13 | 14 | private int height; 15 | 16 | private int[] mBitmap2; 17 | 18 | private int[] mBitmap1; 19 | 20 | private float wavelength = 36; 21 | private float amplitude = 10; 22 | private float phase = 0; 23 | private int radius = 5; 24 | 25 | private int radius2 = 0; 26 | private int icentreX; 27 | private int icentreY; 28 | 29 | private int alpha = 255; 30 | private Paint mPaint; 31 | private boolean flag = true; 32 | private Activity mActivity; 33 | 34 | private int SCALE = 3; 35 | 36 | public DrawWaterWaveWithSina(Activity context, Bitmap bmp) { 37 | super(context); 38 | mPaint = new Paint(); 39 | Bitmap image = bmp; 40 | width = image.getWidth() / SCALE; 41 | height = image.getHeight() / SCALE; 42 | mActivity = context; 43 | mBitmap2 = new int[width * height]; 44 | mBitmap1 = new int[width * height]; 45 | 46 | Bitmap scaledBitmap = Bitmap.createScaledBitmap(image, width, height, false); 47 | 48 | scaledBitmap.getPixels(mBitmap1, 0, width, 0, 0, width, height); 49 | for (int i = 0; i < width * height; i++) { 50 | mBitmap2[i] = mBitmap1[i]; 51 | } 52 | setImageBitmap(Bitmap.createBitmap(mBitmap2, 0, width, width, height, Bitmap.Config.ARGB_8888)); 53 | 54 | } 55 | 56 | // protected void onDraw(Canvas canvas) { 57 | // canvas.drawBitmap(mBitmap2, 0, width, 0, 0, width, height, true, mPaint); 58 | // super.onDraw(canvas); 59 | // } 60 | 61 | // @Override 62 | // public boolean onTouchEvent(MotionEvent event) { 63 | // 64 | // if (event.getAction() == MotionEvent.ACTION_DOWN && !isRunning) { 65 | // start((int)event.getX(), (int)event.getY()); 66 | // } 67 | // 68 | // return super.onTouchEvent(event); 69 | // } 70 | 71 | private boolean transformInverse(int x, int y, int[] out) { 72 | int dx = x - icentreX; 73 | int dy = y - icentreY; 74 | int distance2 = dx * dx + dy * dy; 75 | 76 | if (distance2 > radius2) { 77 | out[0] = x; 78 | out[1] = y; 79 | out[2] = 0; 80 | return false; 81 | } else { 82 | float distance = (float)Math.sqrt(distance2); 83 | float amount = amplitude * (float)Math.sin(distance / wavelength * TWO_PI - phase / TWO_PI); 84 | // float amount = amplitude * (float)Math.sin(distance / WT - PW); 85 | amount *= (radius - distance) / radius; 86 | // if (distance != 0) 87 | // amount *= wavelength / distance; 88 | out[0] = (int)(x + dx * amount); 89 | out[1] = (int)(y + dy * amount); 90 | out[2] = (int)distance; 91 | return true; 92 | } 93 | } 94 | 95 | private void createNextBitmap() { 96 | int[] temp = new int[3]; 97 | for (int i = 0; i < width; i++) 98 | for (int j = 0; j < height; j++) { 99 | if (transformInverse(i, j, temp)) { 100 | if (temp[0] >= width || temp[1] >= height || temp[0] < 0 || temp[1] < 0) { 101 | mBitmap2[j * width + i] = 0x00000000; 102 | } else { 103 | // mBitmap2[j * width + i] = (mBitmap1[temp[1] * width + temp[0]] & 0x00ffffff) 104 | // + (int)((1 - temp[2] / (float)radius) * alpha) << 24; 105 | mBitmap2[j * width + i] = (mBitmap1[temp[1] * width + temp[0]] & 0x00ffffff) 106 | + (alpha << 24); 107 | } 108 | } else { 109 | if (temp[0] >= width || temp[1] >= height || temp[0] < 0 || temp[1] < 0) { 110 | mBitmap2[j * width + i] = 0x00000000; 111 | } else { 112 | mBitmap2[j * width + i] = mBitmap1[temp[1] * width + temp[0]]; 113 | } 114 | } 115 | 116 | } 117 | } 118 | 119 | @Override 120 | public void run() { 121 | isRunning = true; 122 | while (flag) { 123 | try { 124 | Thread.sleep(30); 125 | } catch (Exception e) { 126 | } 127 | // filter.radius2++; 128 | phase += 5; 129 | radius += 5; 130 | amplitude /= 1.12; 131 | if (amplitude < 0.01) { 132 | stop(); 133 | return; 134 | } 135 | if (alpha > 0) { 136 | alpha -= 5; 137 | } else { 138 | alpha = 0; 139 | } 140 | radius2 = radius * radius; 141 | 142 | long start = System.currentTimeMillis(); 143 | createNextBitmap(); 144 | post(new Runnable() { 145 | 146 | @Override 147 | public void run() { 148 | setImageBitmap(Bitmap.createBitmap(mBitmap2, 0, width, width, height, Bitmap.Config.ARGB_8888)); 149 | 150 | } 151 | }); 152 | 153 | System.out.println("duration:" + (System.currentTimeMillis() - start)); 154 | postInvalidate(); 155 | 156 | } 157 | } 158 | 159 | private void stop() { 160 | flag = false; 161 | if (this.getParent() != null) { 162 | this.post(new Runnable() { 163 | 164 | @Override 165 | public void run() { 166 | mActivity.getWindowManager().removeView(DrawWaterWaveWithSina.this); 167 | } 168 | }); 169 | } 170 | 171 | } 172 | 173 | public void start(int x, int y) { 174 | icentreX = x / SCALE; 175 | icentreY = y / SCALE; 176 | 177 | Thread t = new Thread(this); 178 | t.start(); 179 | } 180 | 181 | } 182 | -------------------------------------------------------------------------------- /src/com/dk/animation/SplitEffect.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorSet; 5 | import android.animation.ObjectAnimator; 6 | import android.app.Activity; 7 | import android.content.Context; 8 | import android.graphics.Bitmap; 9 | import android.graphics.Canvas; 10 | import android.graphics.Paint; 11 | import android.graphics.PixelFormat; 12 | import android.graphics.Rect; 13 | import android.graphics.drawable.BitmapDrawable; 14 | import android.graphics.drawable.Drawable; 15 | import android.os.Handler; 16 | import android.view.Gravity; 17 | import android.view.View; 18 | import android.view.WindowManager; 19 | import android.view.animation.DecelerateInterpolator; 20 | import android.view.animation.Interpolator; 21 | import android.widget.ImageView; 22 | 23 | public class SplitEffect extends BaseEffect { 24 | 25 | public Bitmap mBitmap = null; 26 | private int[] mLoc1; 27 | private int[] mLoc2; 28 | private ImageView mTopImage; 29 | private ImageView mBottomImage; 30 | private AnimatorSet mSetAnim; 31 | 32 | public void prepareAnimation(final Activity destActivity) { 33 | mTopImage = createImageView(destActivity, mBitmap, mLoc1); 34 | mBottomImage = createImageView(destActivity, mBitmap, mLoc2); 35 | } 36 | 37 | public void prepare(Activity currActivity) { 38 | int splitYCoord = -1; 39 | // Get the content of the activity and put in a bitmap 40 | View root = currActivity.getWindow().getDecorView().findViewById(android.R.id.content); 41 | root.setDrawingCacheEnabled(true); 42 | mBitmap = root.getDrawingCache(); 43 | 44 | // If the split Y coordinate is -1 - We'll split the activity equally 45 | splitYCoord = (splitYCoord != -1 ? splitYCoord : mBitmap.getHeight() / 2); 46 | 47 | if (splitYCoord > mBitmap.getHeight()) 48 | throw new IllegalArgumentException("Split Y coordinate [" + splitYCoord + "] exceeds the activity's height [" 49 | + mBitmap.getHeight() + "]"); 50 | 51 | // Set the location to put the 2 bitmaps on the destination activity 52 | mLoc1 = new int[] { 0, splitYCoord, root.getTop() }; 53 | mLoc2 = new int[] { splitYCoord, mBitmap.getHeight(), root.getTop() }; 54 | } 55 | 56 | public void cancel() { 57 | if (mSetAnim != null) 58 | mSetAnim.cancel(); 59 | } 60 | 61 | public void clean(Activity activity) { 62 | if (mTopImage != null) { 63 | mTopImage.setLayerType(View.LAYER_TYPE_NONE, null); 64 | try { 65 | // If we use the regular removeView() we'll get a small UI glitch 66 | activity.getWindowManager().removeViewImmediate(mBottomImage); 67 | } catch (Exception ignored) { 68 | } 69 | } 70 | if (mBottomImage != null) { 71 | mBottomImage.setLayerType(View.LAYER_TYPE_NONE, null); 72 | try { 73 | activity.getWindowManager().removeViewImmediate(mTopImage); 74 | } catch (Exception ignored) { 75 | } 76 | } 77 | 78 | mBitmap = null; 79 | } 80 | 81 | private ImageView createImageView(Activity destActivity, Bitmap bmp, int loc[]) { 82 | MyImageView imageView = new MyImageView(destActivity); 83 | imageView.setImageBitmap(bmp); 84 | imageView.setImageOffsets(bmp.getWidth(), loc[0], loc[1]); 85 | 86 | WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams(); 87 | windowParams.gravity = Gravity.TOP; 88 | windowParams.x = 0; 89 | windowParams.y = loc[2] + loc[0]; 90 | windowParams.height = loc[1] - loc[0]; 91 | windowParams.width = bmp.getWidth(); 92 | windowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 93 | windowParams.format = PixelFormat.TRANSLUCENT; 94 | windowParams.windowAnimations = 0; 95 | destActivity.getWindowManager().addView(imageView, windowParams); 96 | 97 | return imageView; 98 | } 99 | 100 | private class MyImageView extends ImageView { 101 | private Rect mSrcRect; 102 | private Rect mDstRect; 103 | private Paint mPaint; 104 | 105 | public MyImageView(Context context) { 106 | super(context); 107 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 108 | } 109 | 110 | public void setImageOffsets(int width, int startY, int endY) { 111 | mSrcRect = new Rect(0, startY, width, endY); 112 | mDstRect = new Rect(0, 0, width, endY - startY); 113 | } 114 | 115 | @Override 116 | protected void onDraw(Canvas canvas) { 117 | Bitmap bm = null; 118 | Drawable drawable = getDrawable(); 119 | if (null != drawable && drawable instanceof BitmapDrawable) { 120 | bm = ((BitmapDrawable)drawable).getBitmap(); 121 | } 122 | 123 | if (null == bm) { 124 | super.onDraw(canvas); 125 | } else { 126 | canvas.drawBitmap(bm, mSrcRect, mDstRect, mPaint); 127 | } 128 | } 129 | } 130 | 131 | public void animate(final Activity destActivity, final int duration) { 132 | final Interpolator interpolator = new DecelerateInterpolator(); 133 | destActivity.getWindow().setFlags( 134 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, 135 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); 136 | 137 | 138 | new Handler().post(new Runnable() { 139 | 140 | @Override 141 | public void run() { 142 | mSetAnim = new AnimatorSet(); 143 | mTopImage.setLayerType(View.LAYER_TYPE_HARDWARE, null); 144 | mBottomImage.setLayerType(View.LAYER_TYPE_HARDWARE, null); 145 | mSetAnim.addListener(new Animator.AnimatorListener() { 146 | @Override 147 | public void onAnimationStart(Animator animation) { 148 | } 149 | 150 | @Override 151 | public void onAnimationEnd(Animator animation) { 152 | clean(destActivity); 153 | } 154 | 155 | @Override 156 | public void onAnimationCancel(Animator animation) { 157 | clean(destActivity); 158 | } 159 | 160 | @Override 161 | public void onAnimationRepeat(Animator animation) { 162 | 163 | } 164 | }); 165 | 166 | Animator anim1 = ObjectAnimator.ofFloat(mTopImage, "translationY", mTopImage.getHeight() * -1); 167 | Animator anim2 = ObjectAnimator.ofFloat(mBottomImage, "translationY", mBottomImage.getHeight()); 168 | 169 | if (interpolator != null) { 170 | anim1.setInterpolator(interpolator); 171 | anim2.setInterpolator(interpolator); 172 | } 173 | 174 | mSetAnim.setDuration(duration); 175 | mSetAnim.playTogether(anim1, anim2); 176 | mSetAnim.start(); 177 | 178 | } 179 | }); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/com/dk/animation/folding/FoldingLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Priboi Tiberiu 3 | * Copyright (C) 2013 The Android Open Source Project 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.dk.animation.folding; 19 | 20 | 21 | import android.content.Context; 22 | import android.util.AttributeSet; 23 | import android.view.GestureDetector; 24 | import android.view.MotionEvent; 25 | import android.view.View; 26 | import android.view.ViewConfiguration; 27 | 28 | /** 29 | * The folding layout where the number of folds, the anchor point and the 30 | * orientation of the fold can be specified. Each of these parameters can be 31 | * modified individually and updates and resets the fold to a default (unfolded) 32 | * state. The fold factor varies between 0 (completely unfolded flat image) to 33 | * 1.0 (completely folded, non-visible image). 34 | * 35 | * This layout throws an exception if there is more than one child added to the 36 | * view. For more complicated view hierarchy's inside the folding layout, the 37 | * views should all be nested inside 1 parent layout. 38 | * 39 | * This layout folds the contents of its child in real time. By applying matrix 40 | * transformations when drawing to canvas, the contents of the child may change 41 | * as the fold takes place. It is important to note that there are jagged edges 42 | * about the perimeter of the layout as a result of applying transformations to 43 | * a rectangle. This can be avoided by having the child of this layout wrap its 44 | * content inside a 1 pixel transparent border. This will cause an anti-aliasing 45 | * like effect and smoothen out the edges. 46 | * 47 | */ 48 | public class FoldingLayout extends BaseFoldingLayout { 49 | 50 | private final String FOLDING_VIEW_EXCEPTION_MESSAGE = "Folding Layout can only 1 child at " 51 | + "most"; 52 | 53 | private GestureDetector mScrollGestureDetector; 54 | 55 | FoldingLayout that = null; 56 | 57 | private int mTranslation = 0; 58 | private int mParentPositionY = -1; 59 | private int mTouchSlop = -1; 60 | private boolean mDidNotStartScroll = true; 61 | 62 | public FoldingLayout(Context context) { 63 | super(context); 64 | init(context, null); 65 | that = this; 66 | } 67 | 68 | public FoldingLayout(Context context, AttributeSet attrs) { 69 | super(context, attrs); 70 | init(context, attrs); 71 | that = this; 72 | } 73 | 74 | public FoldingLayout(Context context, AttributeSet attrs, int defStyle) { 75 | super(context, attrs, defStyle); 76 | init(context, attrs); 77 | that = this; 78 | } 79 | 80 | public void init(Context context, AttributeSet attrs) { 81 | mScrollGestureDetector = new GestureDetector(context, 82 | new ScrollGestureDetector()); 83 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 84 | setAnchorFactor(0); 85 | super.init(context, attrs); 86 | } 87 | 88 | @Override 89 | protected boolean addViewInLayout(View child, int index, 90 | LayoutParams params, boolean preventRequestLayout) { 91 | throwCustomException(getChildCount()); 92 | boolean returnValue = super.addViewInLayout(child, index, params, 93 | preventRequestLayout); 94 | return returnValue; 95 | } 96 | 97 | /** 98 | * The custom exception to be thrown so as to limit the number of views in 99 | * this layout to at most one. 100 | */ 101 | private class NumberOfFoldingLayoutChildrenException extends 102 | RuntimeException { 103 | /** 104 | * 105 | */ 106 | private static final long serialVersionUID = 1L; 107 | 108 | public NumberOfFoldingLayoutChildrenException(String message) { 109 | super(message); 110 | } 111 | } 112 | 113 | /** 114 | * Throws an exception if the number of views added to this layout exceeds 115 | * one. 116 | */ 117 | private void throwCustomException(int numOfChildViews) { 118 | if (numOfChildViews == 1) { 119 | throw new NumberOfFoldingLayoutChildrenException( 120 | FOLDING_VIEW_EXCEPTION_MESSAGE); 121 | } 122 | } 123 | 124 | /** This class uses user touch events to fold and unfold the folding view. */ 125 | private class ScrollGestureDetector extends 126 | GestureDetector.SimpleOnGestureListener { 127 | @Override 128 | public boolean onDown(MotionEvent e) { 129 | mDidNotStartScroll = true; 130 | return true; 131 | } 132 | 133 | /** 134 | * All the logic here is used to determine by what factor the paper view 135 | * should be folded in response to the user's touch events. The logic 136 | * here uses vertical scrolling to fold a vertically oriented view and 137 | * horizontal scrolling to fold a horizontally oriented fold. Depending 138 | * on where the anchor point of the fold is, movements towards or away 139 | * from the anchor point will either fold or unfold the paper 140 | * respectively. 141 | * 142 | * The translation logic here also accounts for the touch slop when a 143 | * new user touch begins, but before a scroll event is first invoked. 144 | */ 145 | @Override 146 | public boolean onScroll(MotionEvent e1, MotionEvent e2, 147 | float distanceX, float distanceY) { 148 | int touchSlop = 0; 149 | float factor; 150 | if (mOrientation == Orientation.VERTICAL) { 151 | factor = Math.abs((float) (mTranslation) 152 | / (float) (that.getHeight())); 153 | 154 | if (e2.getY() - mParentPositionY <= that.getHeight() 155 | && e2.getY() - mParentPositionY >= 0) { 156 | if ((e2.getY() - mParentPositionY) > that.getHeight() 157 | * getAnchorFactor()) { 158 | mTranslation -= (int) distanceY; 159 | touchSlop = distanceY < 0 ? -mTouchSlop : mTouchSlop; 160 | } else { 161 | mTranslation += (int) distanceY; 162 | touchSlop = distanceY < 0 ? mTouchSlop : -mTouchSlop; 163 | } 164 | mTranslation = mDidNotStartScroll ? mTranslation 165 | + touchSlop : mTranslation; 166 | 167 | if (mTranslation < -that.getHeight()) { 168 | mTranslation = -that.getHeight(); 169 | } 170 | } 171 | } else { 172 | factor = Math.abs(((float) mTranslation) 173 | / ((float) that.getWidth())); 174 | 175 | if (e2.getRawX() > that.getWidth() * getAnchorFactor()) { 176 | mTranslation -= (int) distanceX; 177 | touchSlop = distanceX < 0 ? -mTouchSlop : mTouchSlop; 178 | } else { 179 | mTranslation += (int) distanceX; 180 | touchSlop = distanceX < 0 ? mTouchSlop : -mTouchSlop; 181 | } 182 | mTranslation = mDidNotStartScroll ? mTranslation + touchSlop 183 | : mTranslation; 184 | 185 | if (mTranslation < -that.getWidth()) { 186 | mTranslation = -that.getWidth(); 187 | } 188 | } 189 | 190 | mDidNotStartScroll = false; 191 | 192 | if (mTranslation > 0) { 193 | mTranslation = 0; 194 | } 195 | 196 | that.setFoldFactor(factor); 197 | 198 | return true; 199 | } 200 | } 201 | 202 | @Override 203 | public boolean onTouchEvent(MotionEvent me) { 204 | return mScrollGestureDetector.onTouchEvent(me); 205 | } 206 | 207 | } -------------------------------------------------------------------------------- /src/com/dk/animation/BlurEffect.java: -------------------------------------------------------------------------------- 1 | package com.dk.animation; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Activity; 5 | import android.content.Context; 6 | import android.graphics.Bitmap; 7 | import android.graphics.Camera; 8 | import android.graphics.Canvas; 9 | import android.graphics.Matrix; 10 | import android.graphics.Paint; 11 | import android.graphics.PixelFormat; 12 | import android.os.Build.VERSION; 13 | import android.os.Handler; 14 | import android.os.Message; 15 | import android.renderscript.Allocation; 16 | import android.renderscript.Element; 17 | import android.renderscript.RenderScript; 18 | import android.renderscript.ScriptIntrinsicBlur; 19 | import android.view.Gravity; 20 | import android.view.View; 21 | import android.view.WindowManager; 22 | import android.widget.ImageView; 23 | import android.widget.ImageView.ScaleType; 24 | 25 | public class BlurEffect extends BaseEffect { 26 | 27 | private Bitmap mBitmap = null; 28 | private Bitmap mScaledBitmap = null; 29 | private ImageView mTopImage; 30 | private int top; 31 | 32 | public void prepareAnimation(final Activity destActivity) { 33 | mTopImage = createImageView(destActivity, mBitmap); 34 | } 35 | 36 | public void prepare(Activity currActivity) { 37 | View root = currActivity.getWindow().getDecorView().findViewById(android.R.id.content); 38 | top = root.getTop(); 39 | root.setDrawingCacheEnabled(true); 40 | mBitmap = root.getDrawingCache(); 41 | scaleBitmap(mBitmap); 42 | } 43 | 44 | private void scaleBitmap(Bitmap bmp) { 45 | mScaledBitmap = Bitmap.createScaledBitmap(bmp, bmp.getWidth() / 8, bmp.getWidth() / 8, true); 46 | 47 | } 48 | 49 | public void cancel() { 50 | } 51 | 52 | public void clean(Activity activity) { 53 | if (mTopImage != null) { 54 | mTopImage.setLayerType(View.LAYER_TYPE_NONE, null); 55 | try { 56 | // If we use the regular removeView() we'll get a small UI glitch 57 | activity.getWindowManager().removeViewImmediate(mTopImage); 58 | } catch (Exception ignored) { 59 | } 60 | } 61 | mBitmap = null; 62 | } 63 | 64 | private ImageView createImageView(Activity destActivity, Bitmap bmp) { 65 | ImageView imageView = new ImageView(destActivity); 66 | imageView.setImageBitmap(bmp); 67 | imageView.setScaleType(ScaleType.FIT_XY); 68 | WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams(); 69 | windowParams.gravity = Gravity.TOP; 70 | windowParams.x = 0; 71 | windowParams.y = top; 72 | windowParams.height = bmp.getHeight(); 73 | windowParams.width = bmp.getWidth(); 74 | windowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 75 | windowParams.format = PixelFormat.TRANSLUCENT; 76 | windowParams.windowAnimations = 0; 77 | destActivity.getWindowManager().addView(imageView, windowParams); 78 | 79 | return imageView; 80 | } 81 | 82 | public void animate(final Activity destActivity, final int duration) { 83 | 84 | new Handler().post(new Runnable() { 85 | private int alpha = 255; 86 | 87 | @Override 88 | public void run() { 89 | 90 | final Handler callBack = new Handler() { 91 | 92 | @Override 93 | public void handleMessage(Message msg) { 94 | switch (msg.what) { 95 | case 101: 96 | mTopImage.setAlpha(alpha); 97 | mTopImage.setImageBitmap(mScaledBitmap); 98 | System.out.println("refresh:" + alpha); 99 | break; 100 | case 102: 101 | clean(destActivity); 102 | break; 103 | } 104 | } 105 | }; 106 | 107 | Thread animationThread = new Thread(new Runnable() { 108 | 109 | @Override 110 | public void run() { 111 | while (alpha > 0) { 112 | if (alpha > 180) { 113 | alpha -= 8; 114 | } else { 115 | alpha -= 25; 116 | } 117 | if (alpha > 0) { 118 | mScaledBitmap = apply(destActivity, mScaledBitmap, 3); 119 | 120 | } 121 | 122 | callBack.sendEmptyMessage(101); 123 | 124 | try { 125 | Thread.sleep(50); 126 | } catch (InterruptedException e) { 127 | e.printStackTrace(); 128 | } 129 | } 130 | 131 | callBack.sendEmptyMessage(102); 132 | } 133 | }); 134 | 135 | animationThread.start(); 136 | 137 | } 138 | }); 139 | } 140 | 141 | // blur effect 142 | private static int DEFAULT_BLUR_RADIUS = 7; 143 | 144 | public static Bitmap apply(Context context, Bitmap sentBitmap) { 145 | return apply(context, sentBitmap, DEFAULT_BLUR_RADIUS); 146 | } 147 | 148 | @SuppressLint("NewApi") 149 | public static Bitmap apply(Context context, Bitmap sentBitmap, int radius) { 150 | if (VERSION.SDK_INT > 16) { 151 | Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); 152 | 153 | final RenderScript rs = RenderScript.create(context); 154 | final Allocation input = Allocation.createFromBitmap(rs, sentBitmap, Allocation.MipmapControl.MIPMAP_NONE, 155 | Allocation.USAGE_SCRIPT); 156 | final Allocation output = Allocation.createTyped(rs, input.getType()); 157 | final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); 158 | script.setRadius(radius); 159 | script.setInput(input); 160 | script.forEach(output); 161 | output.copyTo(bitmap); 162 | return bitmap; 163 | } 164 | 165 | // Stack Blur v1.0 from 166 | // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html 167 | // 168 | // Java Author: Mario Klingemann 169 | // http://incubator.quasimondo.com 170 | // created Feburary 29, 2004 171 | // Android port : Yahel Bouaziz 172 | // http://www.kayenko.com 173 | // ported april 5th, 2012 174 | 175 | // This is a compromise between Gaussian Blur and Box blur 176 | // It creates much better looking blurs than Box Blur, but is 177 | // 7x faster than my Gaussian Blur implementation. 178 | // 179 | // I called it Stack Blur because this describes best how this 180 | // filter works internally: it creates a kind of moving stack 181 | // of colors whilst scanning through the image. Thereby it 182 | // just has to add one new block of color to the right side 183 | // of the stack and remove the leftmost color. The remaining 184 | // colors on the topmost layer of the stack are either added on 185 | // or reduced by one, depending on if they are on the right or 186 | // on the left side of the stack. 187 | // 188 | // If you are using this algorithm in your code please add 189 | // the following line: 190 | // 191 | // Stack Blur Algorithm by Mario Klingemann 192 | 193 | Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); 194 | 195 | if (radius < 1) { 196 | return (null); 197 | } 198 | 199 | int w = bitmap.getWidth(); 200 | int h = bitmap.getHeight(); 201 | 202 | int[] pix = new int[w * h]; 203 | bitmap.getPixels(pix, 0, w, 0, 0, w, h); 204 | 205 | int wm = w - 1; 206 | int hm = h - 1; 207 | int wh = w * h; 208 | int div = radius + radius + 1; 209 | 210 | int r[] = new int[wh]; 211 | int g[] = new int[wh]; 212 | int b[] = new int[wh]; 213 | int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; 214 | int vmin[] = new int[Math.max(w, h)]; 215 | 216 | int divsum = (div + 1) >> 1; 217 | divsum *= divsum; 218 | int dv[] = new int[256 * divsum]; 219 | for (i = 0; i < 256 * divsum; i++) { 220 | dv[i] = (i / divsum); 221 | } 222 | 223 | yw = yi = 0; 224 | 225 | int[][] stack = new int[div][3]; 226 | int stackpointer; 227 | int stackstart; 228 | int[] sir; 229 | int rbs; 230 | int r1 = radius + 1; 231 | int routsum, goutsum, boutsum; 232 | int rinsum, ginsum, binsum; 233 | 234 | for (y = 0; y < h; y++) { 235 | rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; 236 | for (i = -radius; i <= radius; i++) { 237 | p = pix[yi + Math.min(wm, Math.max(i, 0))]; 238 | sir = stack[i + radius]; 239 | sir[0] = (p & 0xff0000) >> 16; 240 | sir[1] = (p & 0x00ff00) >> 8; 241 | sir[2] = (p & 0x0000ff); 242 | rbs = r1 - Math.abs(i); 243 | rsum += sir[0] * rbs; 244 | gsum += sir[1] * rbs; 245 | bsum += sir[2] * rbs; 246 | if (i > 0) { 247 | rinsum += sir[0]; 248 | ginsum += sir[1]; 249 | binsum += sir[2]; 250 | } else { 251 | routsum += sir[0]; 252 | goutsum += sir[1]; 253 | boutsum += sir[2]; 254 | } 255 | } 256 | stackpointer = radius; 257 | 258 | for (x = 0; x < w; x++) { 259 | 260 | r[yi] = dv[rsum]; 261 | g[yi] = dv[gsum]; 262 | b[yi] = dv[bsum]; 263 | 264 | rsum -= routsum; 265 | gsum -= goutsum; 266 | bsum -= boutsum; 267 | 268 | stackstart = stackpointer - radius + div; 269 | sir = stack[stackstart % div]; 270 | 271 | routsum -= sir[0]; 272 | goutsum -= sir[1]; 273 | boutsum -= sir[2]; 274 | 275 | if (y == 0) { 276 | vmin[x] = Math.min(x + radius + 1, wm); 277 | } 278 | p = pix[yw + vmin[x]]; 279 | 280 | sir[0] = (p & 0xff0000) >> 16; 281 | sir[1] = (p & 0x00ff00) >> 8; 282 | sir[2] = (p & 0x0000ff); 283 | 284 | rinsum += sir[0]; 285 | ginsum += sir[1]; 286 | binsum += sir[2]; 287 | 288 | rsum += rinsum; 289 | gsum += ginsum; 290 | bsum += binsum; 291 | 292 | stackpointer = (stackpointer + 1) % div; 293 | sir = stack[(stackpointer) % div]; 294 | 295 | routsum += sir[0]; 296 | goutsum += sir[1]; 297 | boutsum += sir[2]; 298 | 299 | rinsum -= sir[0]; 300 | ginsum -= sir[1]; 301 | binsum -= sir[2]; 302 | 303 | yi++; 304 | } 305 | yw += w; 306 | } 307 | for (x = 0; x < w; x++) { 308 | rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; 309 | yp = -radius * w; 310 | for (i = -radius; i <= radius; i++) { 311 | yi = Math.max(0, yp) + x; 312 | 313 | sir = stack[i + radius]; 314 | 315 | sir[0] = r[yi]; 316 | sir[1] = g[yi]; 317 | sir[2] = b[yi]; 318 | 319 | rbs = r1 - Math.abs(i); 320 | 321 | rsum += r[yi] * rbs; 322 | gsum += g[yi] * rbs; 323 | bsum += b[yi] * rbs; 324 | 325 | if (i > 0) { 326 | rinsum += sir[0]; 327 | ginsum += sir[1]; 328 | binsum += sir[2]; 329 | } else { 330 | routsum += sir[0]; 331 | goutsum += sir[1]; 332 | boutsum += sir[2]; 333 | } 334 | 335 | if (i < hm) { 336 | yp += w; 337 | } 338 | } 339 | yi = x; 340 | stackpointer = radius; 341 | for (y = 0; y < h; y++) { 342 | // Preserve alpha channel: ( 0xff000000 & pix[yi] ) 343 | pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum]; 344 | 345 | rsum -= routsum; 346 | gsum -= goutsum; 347 | bsum -= boutsum; 348 | 349 | stackstart = stackpointer - radius + div; 350 | sir = stack[stackstart % div]; 351 | 352 | routsum -= sir[0]; 353 | goutsum -= sir[1]; 354 | boutsum -= sir[2]; 355 | 356 | if (x == 0) { 357 | vmin[y] = Math.min(y + r1, hm) * w; 358 | } 359 | p = x + vmin[y]; 360 | 361 | sir[0] = r[p]; 362 | sir[1] = g[p]; 363 | sir[2] = b[p]; 364 | 365 | rinsum += sir[0]; 366 | ginsum += sir[1]; 367 | binsum += sir[2]; 368 | 369 | rsum += rinsum; 370 | gsum += ginsum; 371 | bsum += binsum; 372 | 373 | stackpointer = (stackpointer + 1) % div; 374 | sir = stack[stackpointer]; 375 | 376 | routsum += sir[0]; 377 | goutsum += sir[1]; 378 | boutsum += sir[2]; 379 | 380 | rinsum -= sir[0]; 381 | ginsum -= sir[1]; 382 | binsum -= sir[2]; 383 | 384 | yi += w; 385 | } 386 | } 387 | 388 | bitmap.setPixels(pix, 0, w, 0, 0, w, h); 389 | return (bitmap); 390 | } 391 | 392 | } 393 | -------------------------------------------------------------------------------- /src/com/dk/animation/folding/BaseFoldingLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Priboi Tiberiu 3 | * Copyright (C) 2013 The Android Open Source Project 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.dk.animation.folding; 19 | 20 | import com.dk.animation.R; 21 | 22 | import android.content.Context; 23 | import android.content.res.TypedArray; 24 | import android.graphics.Bitmap; 25 | import android.graphics.Canvas; 26 | import android.graphics.Color; 27 | import android.graphics.LinearGradient; 28 | import android.graphics.Matrix; 29 | import android.graphics.Paint; 30 | import android.graphics.Paint.Style; 31 | import android.graphics.Rect; 32 | import android.graphics.Shader.TileMode; 33 | import android.util.AttributeSet; 34 | import android.view.View; 35 | import android.view.ViewGroup; 36 | 37 | 38 | /** 39 | * The folding layout where the number of folds, the anchor point and the 40 | * orientation of the fold can be specified. Each of these parameters can be 41 | * modified individually and updates and resets the fold to a default (unfolded) 42 | * state. The fold factor varies between 0 (completely unfolded flat image) to 43 | * 1.0 (completely folded, non-visible image). 44 | * 45 | * This layout throws an exception if there is more than one child added to the 46 | * view. For more complicated view hierarchy's inside the folding layout, the 47 | * views should all be nested inside 1 parent layout. 48 | * 49 | * This layout folds the contents of its child in real time. By applying matrix 50 | * transformations when drawing to canvas, the contents of the child may change 51 | * as the fold takes place. It is important to note that there are jagged edges 52 | * about the perimeter of the layout as a result of applying transformations to 53 | * a rectangle. This can be avoided by having the child of this layout wrap its 54 | * content inside a 1 pixel transparent border. This will cause an anti-aliasing 55 | * like effect and smoothen out the edges. 56 | * 57 | */ 58 | public class BaseFoldingLayout extends ViewGroup { 59 | 60 | /* 61 | * A bug was introduced in Android 4.3 that ignores changes to the Canvas 62 | * state between multiple calls to super.dispatchDraw() when running with 63 | * hardware acceleration. To account for this bug, a slightly different 64 | * approach was taken to fold a static image whereby a bitmap of the 65 | * original contents is captured and drawn in segments onto the canvas. 66 | * However, this method does not permit the folding of a TextureView hosting 67 | * a live camera feed which continuously updates. Furthermore, the sepia 68 | * effect was removed from the bitmap variation of the demo to simplify the 69 | * logic when running with this workaround." 70 | */ 71 | 72 | public static enum Orientation { 73 | VERTICAL, HORIZONTAL 74 | } 75 | 76 | private final String FOLDING_VIEW_EXCEPTION_MESSAGE = "Folding Layout can only 1 child at " 77 | + "most"; 78 | 79 | private final float SHADING_ALPHA = 0.8f; 80 | private final float SHADING_FACTOR = 0.5f; 81 | private final int DEPTH_CONSTANT = 1500; 82 | private final int NUM_OF_POLY_POINTS = 8; 83 | 84 | private Rect[] mFoldRectArray; 85 | 86 | private Matrix[] mMatrix; 87 | 88 | protected Orientation mOrientation = Orientation.HORIZONTAL; 89 | 90 | protected float mAnchorFactor = 0; 91 | private float mFoldFactor = 0; 92 | 93 | private int mNumberOfFolds = 2; 94 | 95 | private boolean mIsHorizontal = true; 96 | 97 | private int mOriginalWidth = 0; 98 | private int mOriginalHeight = 0; 99 | 100 | private float mFoldMaxWidth = 0; 101 | private float mFoldMaxHeight = 0; 102 | private float mFoldDrawWidth = 0; 103 | private float mFoldDrawHeight = 0; 104 | 105 | private boolean mIsFoldPrepared = false; 106 | private boolean mShouldDraw = true; 107 | 108 | private Paint mSolidShadow; 109 | private Paint mGradientShadow; 110 | private LinearGradient mShadowLinearGradient; 111 | private Matrix mShadowGradientMatrix; 112 | 113 | private float[] mSrc; 114 | private float[] mDst; 115 | 116 | private OnFoldListener mFoldListener; 117 | 118 | private float mPreviousFoldFactor = 0; 119 | 120 | private Bitmap mFullBitmap; 121 | private Rect mDstRect; 122 | 123 | public BaseFoldingLayout(Context context) { 124 | super(context); 125 | } 126 | 127 | public BaseFoldingLayout(Context context, AttributeSet attrs) { 128 | super(context, attrs); 129 | init(context, attrs); 130 | } 131 | 132 | public BaseFoldingLayout(Context context, AttributeSet attrs, int defStyle) { 133 | super(context, attrs, defStyle); 134 | init(context, attrs); 135 | } 136 | 137 | public void init(Context context, AttributeSet attrs) { 138 | // now style everything! 139 | TypedArray ta = context.obtainStyledAttributes(attrs, 140 | R.styleable.FoldingMenu); 141 | int mFoldNumber = ta.getInt(R.styleable.FoldingMenu_foldNumber, 142 | mNumberOfFolds); 143 | if (mFoldNumber > 0 && mFoldNumber < 7) { 144 | mNumberOfFolds = mFoldNumber; 145 | } else { 146 | mNumberOfFolds = 2; 147 | } 148 | ta.recycle(); 149 | } 150 | 151 | @Override 152 | protected boolean addViewInLayout(View child, int index, 153 | LayoutParams params, boolean preventRequestLayout) { 154 | throwCustomException(getChildCount()); 155 | boolean returnValue = super.addViewInLayout(child, index, params, 156 | preventRequestLayout); 157 | return returnValue; 158 | } 159 | 160 | @Override 161 | public void addView(View child, int index, LayoutParams params) { 162 | throwCustomException(getChildCount()); 163 | super.addView(child, index, params); 164 | } 165 | 166 | @Override 167 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 168 | View child = getChildAt(0); 169 | measureChild(child, widthMeasureSpec, heightMeasureSpec); 170 | setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); 171 | } 172 | 173 | @Override 174 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 175 | View child = getChildAt(0); 176 | child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight()); 177 | updateFold(); 178 | } 179 | 180 | /** 181 | * The custom exception to be thrown so as to limit the number of views in 182 | * this layout to at most one. 183 | */ 184 | private class NumberOfFoldingLayoutChildrenException extends 185 | RuntimeException { 186 | /** 187 | * 188 | */ 189 | private static final long serialVersionUID = 1L; 190 | 191 | public NumberOfFoldingLayoutChildrenException(String message) { 192 | super(message); 193 | } 194 | } 195 | 196 | /** 197 | * Throws an exception if the number of views added to this layout exceeds 198 | * one. 199 | */ 200 | private void throwCustomException(int numOfChildViews) { 201 | if (numOfChildViews == 1) { 202 | throw new NumberOfFoldingLayoutChildrenException( 203 | FOLDING_VIEW_EXCEPTION_MESSAGE); 204 | } 205 | } 206 | 207 | public void setFoldListener(OnFoldListener foldListener) { 208 | mFoldListener = foldListener; 209 | } 210 | 211 | /** 212 | * Sets the fold factor of the folding view and updates all the 213 | * corresponding matrices and values to account for the new fold factor. 214 | * Once that is complete, it redraws itself with the new fold. 215 | */ 216 | public void setFoldFactor(float foldFactor) { 217 | if (foldFactor != mFoldFactor) { 218 | mFoldFactor = foldFactor; 219 | calculateMatrices(); 220 | invalidate(); 221 | } 222 | } 223 | 224 | 225 | 226 | public void setOrientation(Orientation orientation) { 227 | if (orientation != mOrientation) { 228 | mOrientation = orientation; 229 | updateFold(); 230 | } 231 | } 232 | 233 | public void setAnchorFactor(float anchorFactor) { 234 | if (anchorFactor != mAnchorFactor) { 235 | mAnchorFactor = anchorFactor; 236 | updateFold(); 237 | } 238 | } 239 | 240 | public void setNumberOfFolds(int numberOfFolds) { 241 | if (numberOfFolds != mNumberOfFolds) { 242 | mNumberOfFolds = numberOfFolds; 243 | updateFold(); 244 | } 245 | } 246 | 247 | public float getAnchorFactor() { 248 | return mAnchorFactor; 249 | } 250 | 251 | public Orientation getOrientation() { 252 | return mOrientation; 253 | } 254 | 255 | public float getFoldFactor() { 256 | return mFoldFactor; 257 | } 258 | 259 | public int getNumberOfFolds() { 260 | return mNumberOfFolds; 261 | } 262 | 263 | private void updateFold() { 264 | prepareFold(mOrientation, mAnchorFactor, mNumberOfFolds); 265 | calculateMatrices(); 266 | invalidate(); 267 | } 268 | 269 | /** 270 | * This method is called in order to update the fold's orientation, anchor 271 | * point and number of folds. This creates the necessary setup in order to 272 | * prepare the layout for a fold with the specified parameters. Some of the 273 | * dimensions required for the folding transformation are also acquired 274 | * here. 275 | * 276 | * After this method is called, it will be in a completely unfolded state by 277 | * default. 278 | */ 279 | private void prepareFold(Orientation orientation, float anchorFactor, 280 | int numberOfFolds) { 281 | 282 | mSrc = new float[NUM_OF_POLY_POINTS]; 283 | mDst = new float[NUM_OF_POLY_POINTS]; 284 | 285 | mDstRect = new Rect(); 286 | 287 | mFoldFactor = 0; 288 | mPreviousFoldFactor = 0; 289 | 290 | mIsFoldPrepared = false; 291 | 292 | mSolidShadow = new Paint(); 293 | mGradientShadow = new Paint(); 294 | 295 | mOrientation = orientation; 296 | mIsHorizontal = (orientation == Orientation.HORIZONTAL); 297 | 298 | if (mIsHorizontal) { 299 | mShadowLinearGradient = new LinearGradient(0, 0, SHADING_FACTOR, 0, 300 | Color.BLACK, Color.TRANSPARENT, TileMode.CLAMP); 301 | } else { 302 | mShadowLinearGradient = new LinearGradient(0, 0, 0, SHADING_FACTOR, 303 | Color.BLACK, Color.TRANSPARENT, TileMode.CLAMP); 304 | } 305 | 306 | mGradientShadow.setStyle(Style.FILL); 307 | mGradientShadow.setShader(mShadowLinearGradient); 308 | mShadowGradientMatrix = new Matrix(); 309 | 310 | mAnchorFactor = anchorFactor; 311 | mNumberOfFolds = numberOfFolds; 312 | 313 | mOriginalWidth = getMeasuredWidth(); 314 | mOriginalHeight = getMeasuredHeight(); 315 | 316 | mFoldRectArray = new Rect[mNumberOfFolds]; 317 | mMatrix = new Matrix[mNumberOfFolds]; 318 | 319 | for (int x = 0; x < mNumberOfFolds; x++) { 320 | mMatrix[x] = new Matrix(); 321 | } 322 | 323 | int h = mOriginalHeight; 324 | int w = mOriginalWidth; 325 | 326 | if (Util.IS_JBMR2 &&h!=0 &&w!=0) { 327 | mFullBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 328 | Canvas canvas = new Canvas(mFullBitmap); 329 | getChildAt(0).draw(canvas); 330 | } 331 | 332 | int delta = Math.round(mIsHorizontal ? ((float) w) 333 | / ((float) mNumberOfFolds) : ((float) h) 334 | / ((float) mNumberOfFolds)); 335 | 336 | /* 337 | * Loops through the number of folds and segments the full layout into a 338 | * number of smaller equal components. If the number of folds is odd, 339 | * then one of the components will be smaller than all the rest. Note 340 | * that deltap below handles the calculation for an odd number of folds. 341 | */ 342 | for (int x = 0; x < mNumberOfFolds; x++) { 343 | if (mIsHorizontal) { 344 | int deltap = (x + 1) * delta > w ? w - x * delta : delta; 345 | mFoldRectArray[x] = new Rect(x * delta, 0, x * delta + deltap, 346 | h); 347 | } else { 348 | int deltap = (x + 1) * delta > h ? h - x * delta : delta; 349 | mFoldRectArray[x] = new Rect(0, x * delta, w, x * delta 350 | + deltap); 351 | } 352 | } 353 | 354 | if (mIsHorizontal) { 355 | mFoldMaxHeight = h; 356 | mFoldMaxWidth = delta; 357 | } else { 358 | mFoldMaxHeight = delta; 359 | mFoldMaxWidth = w; 360 | } 361 | 362 | mIsFoldPrepared = true; 363 | } 364 | 365 | /* 366 | * Calculates the transformation matrices used to draw each of the separate 367 | * folding segments from this view. 368 | */ 369 | private void calculateMatrices() { 370 | 371 | mShouldDraw = true; 372 | 373 | if (!mIsFoldPrepared) { 374 | return; 375 | } 376 | 377 | /** 378 | * If the fold factor is 1 than the folding view should not be seen and 379 | * the canvas can be left completely empty. 380 | */ 381 | if (mFoldFactor == 1) { 382 | mShouldDraw = false; 383 | return; 384 | } 385 | 386 | if (mFoldFactor == 0 && mPreviousFoldFactor > 0 387 | && mFoldListener != null) { 388 | 389 | mFoldListener.onEndFold(); 390 | } 391 | 392 | if (mPreviousFoldFactor == 0 && mFoldFactor > 0 393 | && mFoldListener != null) { 394 | 395 | mFoldListener.onStartFold(); 396 | } 397 | 398 | mPreviousFoldFactor = mFoldFactor; 399 | 400 | /* 401 | * Reset all the transformation matrices back to identity before 402 | * computing the new transformation 403 | */ 404 | for (int x = 0; x < mNumberOfFolds; x++) { 405 | mMatrix[x].reset(); 406 | } 407 | 408 | float cTranslationFactor = 1 - mFoldFactor; 409 | 410 | float translatedDistance = mIsHorizontal ? mOriginalWidth 411 | * cTranslationFactor : mOriginalHeight * cTranslationFactor; 412 | 413 | float translatedDistancePerFold = Math.round(translatedDistance 414 | / mNumberOfFolds); 415 | 416 | /* 417 | * For an odd number of folds, the rounding error may cause the 418 | * translatedDistancePerFold to be grater than the max fold width or 419 | * height. 420 | */ 421 | mFoldDrawWidth = mFoldMaxWidth < translatedDistancePerFold ? translatedDistancePerFold 422 | : mFoldMaxWidth; 423 | mFoldDrawHeight = mFoldMaxHeight < translatedDistancePerFold ? translatedDistancePerFold 424 | : mFoldMaxHeight; 425 | 426 | float translatedDistanceFoldSquared = translatedDistancePerFold 427 | * translatedDistancePerFold; 428 | 429 | /* 430 | * Calculate the depth of the fold into the screen using pythagorean 431 | * theorem. 432 | */ 433 | float depth = mIsHorizontal ? (float) Math 434 | .sqrt((double) (mFoldDrawWidth * mFoldDrawWidth - translatedDistanceFoldSquared)) 435 | : (float) Math 436 | .sqrt((double) (mFoldDrawHeight * mFoldDrawHeight - translatedDistanceFoldSquared)); 437 | 438 | /* 439 | * The size of some object is always inversely proportional to the 440 | * distance it is away from the viewpoint. The constant can be varied to 441 | * to affect the amount of perspective. 442 | */ 443 | float scaleFactor = DEPTH_CONSTANT / (DEPTH_CONSTANT + depth); 444 | 445 | float scaledWidth, scaledHeight, bottomScaledPoint, topScaledPoint, rightScaledPoint, leftScaledPoint; 446 | 447 | if (mIsHorizontal) { 448 | scaledWidth = mFoldDrawWidth * cTranslationFactor; 449 | scaledHeight = mFoldDrawHeight * scaleFactor; 450 | } else { 451 | scaledWidth = mFoldDrawWidth * scaleFactor; 452 | scaledHeight = mFoldDrawHeight * cTranslationFactor; 453 | } 454 | 455 | topScaledPoint = (mFoldDrawHeight - scaledHeight) / 2.0f; 456 | bottomScaledPoint = topScaledPoint + scaledHeight; 457 | 458 | leftScaledPoint = (mFoldDrawWidth - scaledWidth) / 2.0f; 459 | rightScaledPoint = leftScaledPoint + scaledWidth; 460 | 461 | float anchorPoint = mIsHorizontal ? mAnchorFactor * mOriginalWidth 462 | : mAnchorFactor * mOriginalHeight; 463 | 464 | /* The fold along which the anchor point is located. */ 465 | float midFold = mIsHorizontal ? (anchorPoint / mFoldDrawWidth) 466 | : anchorPoint / mFoldDrawHeight; 467 | 468 | mSrc[0] = 0; 469 | mSrc[1] = 0; 470 | mSrc[2] = 0; 471 | mSrc[3] = mFoldDrawHeight; 472 | mSrc[4] = mFoldDrawWidth; 473 | mSrc[5] = 0; 474 | mSrc[6] = mFoldDrawWidth; 475 | mSrc[7] = mFoldDrawHeight; 476 | 477 | /* 478 | * Computes the transformation matrix for each fold using the values 479 | * calculated above. 480 | */ 481 | for (int x = 0; x < mNumberOfFolds; x++) { 482 | 483 | boolean isEven = (x % 2 == 0); 484 | 485 | if (mIsHorizontal) { 486 | mDst[0] = (anchorPoint > x * mFoldDrawWidth) ? anchorPoint 487 | + (x - midFold) * scaledWidth : anchorPoint 488 | - (midFold - x) * scaledWidth; 489 | mDst[1] = isEven ? 0 : topScaledPoint; 490 | mDst[2] = mDst[0]; 491 | mDst[3] = isEven ? mFoldDrawHeight : bottomScaledPoint; 492 | mDst[4] = (anchorPoint > (x + 1) * mFoldDrawWidth) ? anchorPoint 493 | + (x + 1 - midFold) * scaledWidth 494 | : anchorPoint - (midFold - x - 1) * scaledWidth; 495 | mDst[5] = isEven ? topScaledPoint : 0; 496 | mDst[6] = mDst[4]; 497 | mDst[7] = isEven ? bottomScaledPoint : mFoldDrawHeight; 498 | 499 | } else { 500 | mDst[0] = isEven ? 0 : leftScaledPoint; 501 | mDst[1] = (anchorPoint > x * mFoldDrawHeight) ? anchorPoint 502 | + (x - midFold) * scaledHeight : anchorPoint 503 | - (midFold - x) * scaledHeight; 504 | mDst[2] = isEven ? leftScaledPoint : 0; 505 | mDst[3] = (anchorPoint > (x + 1) * mFoldDrawHeight) ? anchorPoint 506 | + (x + 1 - midFold) * scaledHeight 507 | : anchorPoint - (midFold - x - 1) * scaledHeight; 508 | mDst[4] = isEven ? mFoldDrawWidth : rightScaledPoint; 509 | mDst[5] = mDst[1]; 510 | mDst[6] = isEven ? rightScaledPoint : mFoldDrawWidth; 511 | mDst[7] = mDst[3]; 512 | } 513 | 514 | /* 515 | * Pixel fractions are present for odd number of folds which need to 516 | * be rounded off here. 517 | */ 518 | for (int y = 0; y < 8; y++) { 519 | mDst[y] = Math.round(mDst[y]); 520 | } 521 | 522 | /* 523 | * If it so happens that any of the folds have reached a point where 524 | * the width or height of that fold is 0, then nothing needs to be 525 | * drawn onto the canvas because the view is essentially completely 526 | * folded. 527 | */ 528 | if (mIsHorizontal) { 529 | if (mDst[4] <= mDst[0] || mDst[6] <= mDst[2]) { 530 | mShouldDraw = false; 531 | return; 532 | } 533 | } else { 534 | if (mDst[3] <= mDst[1] || mDst[7] <= mDst[5]) { 535 | mShouldDraw = false; 536 | return; 537 | } 538 | } 539 | 540 | /* Sets the shadow and bitmap transformation matrices. */ 541 | mMatrix[x].setPolyToPoly(mSrc, 0, mDst, 0, NUM_OF_POLY_POINTS / 2); 542 | } 543 | /* 544 | * The shadows on the folds are split into two parts: Solid shadows and 545 | * gradients. Every other fold has a solid shadow which overlays the 546 | * whole fold. Similarly, the folds in between these alternating folds 547 | * also have an overlaying shadow. However, it is a gradient that takes 548 | * up part of the fold as opposed to a solid shadow overlaying the whole 549 | * fold. 550 | */ 551 | 552 | /* Solid shadow paint object. */ 553 | int alpha = (int) (mFoldFactor * 255 * SHADING_ALPHA); 554 | 555 | mSolidShadow.setColor(Color.argb(alpha, 0, 0, 0)); 556 | 557 | if (mIsHorizontal) { 558 | mShadowGradientMatrix.setScale(mFoldDrawWidth, 1); 559 | mShadowLinearGradient.setLocalMatrix(mShadowGradientMatrix); 560 | } else { 561 | mShadowGradientMatrix.setScale(1, mFoldDrawHeight); 562 | mShadowLinearGradient.setLocalMatrix(mShadowGradientMatrix); 563 | } 564 | 565 | mGradientShadow.setAlpha(alpha); 566 | } 567 | 568 | @Override 569 | protected void dispatchDraw(Canvas canvas) { 570 | /** 571 | * If prepareFold has not been called or if preparation has not 572 | * completed yet, then no custom drawing will take place so only need to 573 | * invoke super's onDraw and return. 574 | */ 575 | if (!mIsFoldPrepared || mFoldFactor == 0) { 576 | super.dispatchDraw(canvas); 577 | return; 578 | } 579 | 580 | if (!mShouldDraw) { 581 | return; 582 | } 583 | 584 | Rect src; 585 | /* 586 | * Draws the bitmaps and shadows on the canvas with the appropriate 587 | * transformations. 588 | */ 589 | for (int x = 0; x < mNumberOfFolds; x++) { 590 | 591 | src = mFoldRectArray[x]; 592 | /* The canvas is saved and restored for every individual fold */ 593 | canvas.save(); 594 | 595 | /* 596 | * Concatenates the canvas with the transformation matrix for the 597 | * the segment of the view corresponding to the actual image being 598 | * displayed. 599 | */ 600 | canvas.concat(mMatrix[x]); 601 | if (Util.IS_JBMR2 ) { 602 | mDstRect.set(0, 0, src.width(), src.height()); 603 | canvas.drawBitmap(mFullBitmap, src, mDstRect, null); 604 | } else { 605 | /* 606 | * The same transformation matrix is used for both the shadow 607 | * and the image segment. The canvas is clipped to account for 608 | * the size of each fold and is translated so they are drawn in 609 | * the right place. The shadow is then drawn on top of the 610 | * different folds using the sametransformation matrix. 611 | */ 612 | canvas.clipRect(0, 0, src.right - src.left, src.bottom 613 | - src.top); 614 | 615 | if (mIsHorizontal) { 616 | canvas.translate(-src.left, 0); 617 | } else { 618 | canvas.translate(0, -src.top); 619 | } 620 | 621 | super.dispatchDraw(canvas); 622 | 623 | if (mIsHorizontal) { 624 | canvas.translate(src.left, 0); 625 | } else { 626 | canvas.translate(0, src.top); 627 | } 628 | } 629 | /* Draws the shadows corresponding to this specific fold. */ 630 | if (x % 2 == 0) { 631 | canvas.drawRect(0, 0, mFoldDrawWidth, mFoldDrawHeight, 632 | mSolidShadow); 633 | } else { 634 | canvas.drawRect(0, 0, mFoldDrawWidth, mFoldDrawHeight, 635 | mGradientShadow); 636 | } 637 | 638 | canvas.restore(); 639 | } 640 | } 641 | 642 | } --------------------------------------------------------------------------------