├── .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 | 
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 |
--------------------------------------------------------------------------------