├── .gitignore ├── AndroidManifest.xml ├── README.md ├── ant.properties ├── build.xml ├── local.properties ├── proguard-project.txt ├── project.properties ├── res ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-ldpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ └── ic_launcher.png ├── layout │ ├── act_one.xml │ └── act_two.xml └── values │ └── strings.xml ├── screenshots └── all.png └── src └── com └── udinic └── ActivitySplitAnimation ├── Activity1.java ├── Activity2.java └── utils └── ActivitySplitAnimationUtil.java /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /.idea 3 | /out 4 | /gen 5 | /**/gen/ 6 | *.iml -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Activity Split Animation 2 | ======================== 3 | 4 | A utility class to create split Activity animation. 5 | 6 | ![screenshots](https://raw.github.com/Udinic/ActivitySplitAnimation/master/screenshots/all.png) 7 | 8 | Usage 9 | ===== 10 | 11 | On Activity A, when you want to call Activity B, use: 12 | 13 | ActivitySplitAnimationUtil.startActivity(Activity1.this, new Intent(Activity1.this, Activity2.class)); 14 | 15 | On Activity B's onCreate(): 16 | 17 | ActivitySplitAnimationUtil.prepareAnimation(this); 18 | 19 | // Setting the Activity's layout 20 | setContentView(R.layout.act_two); 21 | 22 | // Animation duration of 1 second 23 | ActivitySplitAnimationUtil.animate(this, 1000); 24 | 25 | 26 | Developed By 27 | ============ 28 | 29 | * Udi Cohen (udinic@gmail.com) 30 | 31 | 32 | 33 | License 34 | ======= 35 | 36 | Copyright 2013 Udi Cohen 37 | 38 | Licensed under the Apache License, Version 2.0 (the "License"); 39 | you may not use this file except in compliance with the License. 40 | You may obtain a copy of the License at 41 | 42 | http://www.apache.org/licenses/LICENSE-2.0 43 | 44 | Unless required by applicable law or agreed to in writing, software 45 | distributed under the License is distributed on an "AS IS" BASIS, 46 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 47 | See the License for the specific language governing permissions and 48 | limitations under the License. 49 | 50 | [1]: https://raw.github.com/Udinic/ActivitySplitAnimation/master/screenshots/screenshot1.png 51 | -------------------------------------------------------------------------------- /ant.properties: -------------------------------------------------------------------------------- 1 | # This file is used to override default values used by the Ant build system. 2 | # 3 | # This file must be checked into Version Control Systems, as it is 4 | # integral to the build system of your project. 5 | 6 | # This file is only used by the Ant script. 7 | 8 | # You can use this to override default values such as 9 | # 'source.dir' for the location of your java source folder and 10 | # 'out.dir' for the location of your output folder. 11 | 12 | # You can also use it define how the release builds are signed by declaring 13 | # the following properties: 14 | # 'key.store' for the location of your keystore and 15 | # 'key.alias' for the name of the key to use. 16 | # The password will be asked during the build when you use the 'release' target. 17 | 18 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 49 | 50 | 51 | 52 | 56 | 57 | 69 | 70 | 71 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /local.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 *NOT* be checked into Version Control Systems, 5 | # as it contains information specific to your local configuration. 6 | 7 | # location of the SDK. This is only used by Ant 8 | # For customization when using a Version Control System, please read the 9 | # header note. 10 | sdk.dir=D:\\Android\\SDK\\sdk 11 | -------------------------------------------------------------------------------- /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.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-17 15 | -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Udinic/ActivitySplitAnimation/1fd462fded9f258e65632553ff6946e946a88ef3/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Udinic/ActivitySplitAnimation/1fd462fded9f258e65632553ff6946e946a88ef3/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Udinic/ActivitySplitAnimation/1fd462fded9f258e65632553ff6946e946a88ef3/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Udinic/ActivitySplitAnimation/1fd462fded9f258e65632553ff6946e946a88ef3/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/layout/act_one.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /res/layout/act_two.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ActivitySplitAnimation 4 | 5 | -------------------------------------------------------------------------------- /screenshots/all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Udinic/ActivitySplitAnimation/1fd462fded9f258e65632553ff6946e946a88ef3/screenshots/all.png -------------------------------------------------------------------------------- /src/com/udinic/ActivitySplitAnimation/Activity1.java: -------------------------------------------------------------------------------- 1 | package com.udinic.ActivitySplitAnimation; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import com.udinic.ActivitySplitAnimation.utils.ActivitySplitAnimationUtil; 8 | 9 | public class Activity1 extends Activity { 10 | @Override 11 | public void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | setContentView(R.layout.act_one); 14 | 15 | findViewById(R.id.one).setOnClickListener(new View.OnClickListener() { 16 | 17 | @Override 18 | public void onClick(View v) { 19 | ActivitySplitAnimationUtil.startActivity(Activity1.this, new Intent(Activity1.this, Activity2.class)); 20 | } 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/com/udinic/ActivitySplitAnimation/Activity2.java: -------------------------------------------------------------------------------- 1 | package com.udinic.ActivitySplitAnimation; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import com.udinic.ActivitySplitAnimation.utils.ActivitySplitAnimationUtil; 6 | 7 | public class Activity2 extends Activity { 8 | 9 | @Override 10 | protected void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | 13 | // Preparing the 2 images to be split 14 | ActivitySplitAnimationUtil.prepareAnimation(this); 15 | 16 | setContentView(R.layout.act_two); 17 | 18 | // Animating the items to be open, revealing the new activity 19 | ActivitySplitAnimationUtil.animate(this, 1000); 20 | } 21 | 22 | @Override 23 | protected void onStop() { 24 | // If we're currently running the entrance animation - cancel it 25 | ActivitySplitAnimationUtil.cancel(); 26 | 27 | super.onStop(); //To change body of overridden methods use File | Settings | File Templates. 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/com/udinic/ActivitySplitAnimation/utils/ActivitySplitAnimationUtil.java: -------------------------------------------------------------------------------- 1 | package com.udinic.ActivitySplitAnimation.utils; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorSet; 5 | import android.animation.ObjectAnimator; 6 | import android.animation.TimeInterpolator; 7 | import android.app.Activity; 8 | import android.content.Context; 9 | import android.content.Intent; 10 | import android.graphics.Bitmap; 11 | import android.graphics.Canvas; 12 | import android.graphics.Paint; 13 | import android.graphics.PixelFormat; 14 | import android.graphics.Rect; 15 | import android.graphics.drawable.BitmapDrawable; 16 | import android.graphics.drawable.Drawable; 17 | import android.os.Handler; 18 | import android.view.Gravity; 19 | import android.view.View; 20 | import android.view.WindowManager; 21 | import android.view.animation.DecelerateInterpolator; 22 | import android.widget.ImageView; 23 | 24 | /** 25 | * Utility class to create a split activity animation 26 | * 27 | * @author Udi Cohen (@udinic) 28 | */ 29 | public class ActivitySplitAnimationUtil { 30 | 31 | public static Bitmap mBitmap = null; 32 | private static int[] mLoc1; 33 | private static int[] mLoc2; 34 | private static ImageView mTopImage; 35 | private static ImageView mBottomImage; 36 | private static AnimatorSet mSetAnim; 37 | 38 | /** 39 | * Start a new Activity with a Split animation 40 | * 41 | * @param currActivity The current Activity 42 | * @param intent The Intent needed tot start the new Activity 43 | * @param splitYCoord The Y coordinate where we want to split the Activity on the animation. -1 will split the Activity equally 44 | */ 45 | public static void startActivity(Activity currActivity, Intent intent, int splitYCoord) { 46 | 47 | // Preparing the bitmaps that we need to show 48 | prepare(currActivity, splitYCoord); 49 | 50 | currActivity.startActivity(intent); 51 | currActivity.overridePendingTransition(0, 0); 52 | } 53 | 54 | /** 55 | * Start a new Activity with a Split animation right in the middle of the Activity 56 | * 57 | * @param currActivity The current Activity 58 | * @param intent The Intent needed tot start the new Activity 59 | */ 60 | public static void startActivity(Activity currActivity, Intent intent) { 61 | startActivity(currActivity, intent, -1); 62 | } 63 | 64 | /** 65 | * Preparing the graphics on the destination Activity. 66 | * Should be called on the destination activity on Activity#onCreate() BEFORE setContentView() 67 | * 68 | * @param destActivity the destination Activity 69 | */ 70 | public static void prepareAnimation(final Activity destActivity) { 71 | mTopImage = createImageView(destActivity, mBitmap, mLoc1); 72 | mBottomImage = createImageView(destActivity, mBitmap, mLoc2); 73 | } 74 | 75 | /** 76 | * Start the animation the reveals the destination Activity 77 | * Should be called on the destination activity on Activity#onCreate() AFTER setContentView() 78 | * 79 | * @param destActivity the destination Activity 80 | * @param duration The duration of the animation 81 | * @param interpolator The interpulator to use for the animation. null for no interpulation. 82 | */ 83 | public static void animate(final Activity destActivity, final int duration, final TimeInterpolator interpolator) { 84 | 85 | // Post this on the UI thread's message queue. It's needed for the items to be already measured 86 | new Handler().post(new Runnable() { 87 | 88 | @Override 89 | public void run() { 90 | mSetAnim = new AnimatorSet(); 91 | mTopImage.setLayerType(View.LAYER_TYPE_HARDWARE, null); 92 | mBottomImage.setLayerType(View.LAYER_TYPE_HARDWARE, null); 93 | mSetAnim.addListener(new Animator.AnimatorListener() { 94 | @Override 95 | public void onAnimationStart(Animator animation) { 96 | } 97 | 98 | @Override 99 | public void onAnimationEnd(Animator animation) { 100 | clean(destActivity); 101 | } 102 | 103 | @Override 104 | public void onAnimationCancel(Animator animation) { 105 | clean(destActivity); 106 | } 107 | 108 | @Override 109 | public void onAnimationRepeat(Animator animation) { 110 | 111 | } 112 | }); 113 | 114 | // Animating the 2 parts away from each other 115 | Animator anim1 = ObjectAnimator.ofFloat(mTopImage, "translationY", mTopImage.getHeight() * -1); 116 | Animator anim2 = ObjectAnimator.ofFloat(mBottomImage, "translationY", mBottomImage.getHeight()); 117 | 118 | if (interpolator != null) { 119 | anim1.setInterpolator(interpolator); 120 | anim2.setInterpolator(interpolator); 121 | } 122 | 123 | mSetAnim.setDuration(duration); 124 | mSetAnim.playTogether(anim1, anim2); 125 | mSetAnim.start(); 126 | } 127 | }); 128 | } 129 | 130 | /** 131 | * Start the animation that reveals the destination Activity 132 | * Should be called on the destination activity on Activity#onCreate() AFTER setContentView() 133 | * 134 | * @param destActivity the destination Activity 135 | * @param duration The duration of the animation 136 | */ 137 | public static void animate(final Activity destActivity, final int duration) { 138 | animate(destActivity, duration, new DecelerateInterpolator()); 139 | } 140 | 141 | /** 142 | * Cancel an in progress animation 143 | */ 144 | public static void cancel() { 145 | if (mSetAnim != null) 146 | mSetAnim.cancel(); 147 | } 148 | 149 | /** 150 | * Clean stuff 151 | * 152 | * @param activity The Activity where the animation is occurring 153 | */ 154 | private static void clean(Activity activity) { 155 | if (mTopImage != null) { 156 | mTopImage.setLayerType(View.LAYER_TYPE_NONE, null); 157 | try { 158 | // If we use the regular removeView() we'll get a small UI glitch 159 | activity.getWindowManager().removeViewImmediate(mBottomImage); 160 | } catch (Exception ignored) { 161 | } 162 | } 163 | if (mBottomImage != null) { 164 | mBottomImage.setLayerType(View.LAYER_TYPE_NONE, null); 165 | try { 166 | activity.getWindowManager().removeViewImmediate(mTopImage); 167 | } catch (Exception ignored) { 168 | } 169 | } 170 | 171 | mBitmap = null; 172 | } 173 | 174 | /** 175 | * Preparing the graphics for the animation 176 | * 177 | * @param currActivity the current Activity from where we start the new one 178 | * @param splitYCoord The Y coordinate where we want to split the activity. -1 will split the activity equally 179 | */ 180 | private static void prepare(Activity currActivity, int splitYCoord) { 181 | 182 | // Get the content of the activity and put in a bitmap 183 | View root = currActivity.getWindow().getDecorView().findViewById(android.R.id.content); 184 | root.setDrawingCacheEnabled(true); 185 | mBitmap = root.getDrawingCache(); 186 | 187 | // If the split Y coordinate is -1 - We'll split the activity equally 188 | splitYCoord = (splitYCoord != -1 ? splitYCoord : mBitmap.getHeight() / 2); 189 | 190 | if (splitYCoord > mBitmap.getHeight()) 191 | throw new IllegalArgumentException("Split Y coordinate [" + splitYCoord + "] exceeds the activity's height [" + mBitmap.getHeight() + "]"); 192 | 193 | // Set the location to put the 2 bitmaps on the destination activity 194 | mLoc1 = new int[]{0, splitYCoord, root.getTop()}; 195 | mLoc2 = new int[]{splitYCoord, mBitmap.getHeight(), root.getTop()}; 196 | } 197 | 198 | /** 199 | * Creating the an image, containing one part of the animation on the destination activity 200 | * 201 | * @param destActivity The destination activity 202 | * @param bmp The Bitmap of the part we want to add to the destination activity 203 | * @param loc The location this part should be on the screen 204 | * @return 205 | */ 206 | private static ImageView createImageView(Activity destActivity, Bitmap bmp, int loc[]) { 207 | MyImageView imageView = new MyImageView(destActivity); 208 | imageView.setImageBitmap(bmp); 209 | imageView.setImageOffsets(bmp.getWidth(), loc[0], loc[1]); 210 | 211 | WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams(); 212 | windowParams.gravity = Gravity.TOP; 213 | windowParams.x = 0; 214 | windowParams.y = loc[2] + loc[0]; 215 | windowParams.height = loc[1] - loc[0]; 216 | windowParams.width = bmp.getWidth(); 217 | windowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 218 | windowParams.format = PixelFormat.TRANSLUCENT; 219 | windowParams.windowAnimations = 0; 220 | destActivity.getWindowManager().addView(imageView, windowParams); 221 | 222 | return imageView; 223 | } 224 | 225 | /** 226 | * MyImageView 227 | * Extended ImageView that draws just part of an image, base on start/end position 228 | */ 229 | private static class MyImageView extends ImageView 230 | { 231 | private Rect mSrcRect; 232 | private Rect mDstRect; 233 | private Paint mPaint; 234 | 235 | public MyImageView(Context context) 236 | { 237 | super(context); 238 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 239 | } 240 | 241 | /** 242 | * Setting the bitmap offests to control the visible area 243 | * 244 | * @param width The bitmap image 245 | * @param bmp The start Y position 246 | * @param loc The end Y position 247 | * @return 248 | */ 249 | public void setImageOffsets(int width, int startY, int endY) 250 | { 251 | mSrcRect = new Rect(0, startY, width, endY); 252 | mDstRect = new Rect(0, 0, width, endY - startY); 253 | } 254 | 255 | @Override 256 | protected void onDraw(Canvas canvas) 257 | { 258 | Bitmap bm = null; 259 | Drawable drawable = getDrawable(); 260 | if (null != drawable && drawable instanceof BitmapDrawable) 261 | { 262 | bm = ((BitmapDrawable)drawable).getBitmap(); 263 | } 264 | 265 | if (null == bm) 266 | { 267 | super.onDraw(canvas); 268 | } 269 | else 270 | { 271 | canvas.drawBitmap(bm, mSrcRect, mDstRect, mPaint); 272 | } 273 | } 274 | } 275 | } 276 | --------------------------------------------------------------------------------