现在的位置: 首页 > 移动开发> 正文
Android动画设计之ViewOverlay
2013年08月22日 移动开发 暂无评论 ⁄ 被围观 3,915+

什么是ViewOverlay?

ViewOverlay is a class that we can find in Android since its version 4.3 (API version 18) that provides a transparent layer on top of a View, to which you can add visual content and that does not affect the layout hierarchy.

It always has the same size and position as its host view, allowing you to add content over that view.

运行效果

红色部分:使用了 按钮的 parent-parent layout (the main, first-level, layout) ViewGroupOverlay,所以可以穿越整个画面。

橙色部分:没有使用ViewOverlay技术,所以按钮的动画只限定于它的父窗口部分。

绿色部分:结合使用了两种技术,首先是渐变消失,alpha animation from 1f to 0f,然后放在橙色 non-parent ViewOverlay (the orange layout)中,后段动画仅限制与橙色部分。

使用方法

You just have to call the getOverlay() method from any View of your app to get itsViewOverlay, or a ViewGroupOverlay if you are calling this method from someViewGroup object, but both of them uses the same concept.

Once you got it, you can add any View or Drawable that you want to show in this overlay calling add(Drawable drawable) method on ViewOverlay, or add(View view)on ViewGroupOverlay.

ViewOverlay API is so simple, aside from add(Drawable drawable), we can also findclear() and remove(Drawable drawable). These are the only methods that we have to use to handle the views that we move to our ViewOverlays.

优势

Well, for now everything that I came up to my mind to do with this new API can be done using RelativeLayout and  a bit of tricky & ugly code. But this lets us to do that things in a friendly way.

Essentially, this component is visual-only, so views attached to a ViewOverlay will not respond to any touch or tap event. ViewOverlay mechanism was conceived to be used combined with stuff like animations.

Using ViewOverlays we can animate views through other layouts in view hierarchy, even if they are not any of its parents.

So when some of these animations ends, we should have to call clear() orremove(Drawable drawable) methods, to remove the view from our ViewOverlay to keep it clean and avoid memory leaks.

使用限制

Yeah, but…

  • This is only for API 18+, although we hope it will be backported at some support library in the near future.
  • Right now, there is not a single example.

We can not do anything to solve the first point, but today we have been playing with this new stuff to try to understand how it works. So…

程序源码
1.  界面布局 activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
 
<FrameLayout
android:id="@+id/redContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/holo_red_light" >
 
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="ViewOverlay" />
</FrameLayout>
 
<FrameLayout
android:id="@+id/greenContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/holo_orange_light" >
 
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Normal animator" />
</FrameLayout>
 
<FrameLayout
android:id="@+id/orangeContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/holo_green_light" >
 
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="ViewOverlay on other parent" />
</FrameLayout>
 
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >

<FrameLayout
android:id="@+id/redContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/holo_red_light" >

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="ViewOverlay" />
</FrameLayout>

<FrameLayout
android:id="@+id/greenContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/holo_orange_light" >

<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Normal animator" />
</FrameLayout>

<FrameLayout
android:id="@+id/orangeContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/holo_green_light" >

<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="ViewOverlay on other parent" />
</FrameLayout>

</LinearLayout>

2. MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package cat.lafosca.viewoverlaytest;
 
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.widget.Button;
 
public class MainActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewsSetup();
    }
 
    private void viewsSetup() {
        setContentView(R.layout.activity_main);
 
        final Button button = (Button) findViewById(R.id.button);
 
        button.setOnClickListener(new OnClickListener() {
 
            @Override
            public void onClick(View arg0) {
                // Our button is added to the parent of its parent, the most top-level layout
                final ViewGroup container = (ViewGroup) button.getParent().getParent();
                container.getOverlay().add(button);
 
                ObjectAnimator anim = ObjectAnimator.ofFloat(button, "translationY", container.getHeight());
                ObjectAnimator rotate = ObjectAnimator.ofFloat(button, "rotation", 0, 360);
                rotate.setRepeatCount(Animation.INFINITE);
                rotate.setRepeatMode(Animation.REVERSE);
                rotate.setDuration(350);
 
                /*
                 * Button needs to be removed after animation ending
                 * When we have added the view to the ViewOverlay, 
                 * it was removed from its original parent.
                 */
                anim.addListener(new AnimatorListener() {
 
                    @Override
                    public void onAnimationStart(Animator arg0) {
                    }
 
                    @Override
                    public void onAnimationRepeat(Animator arg0) {
                    }
 
                    @Override
                    public void onAnimationEnd(Animator arg0) {
                        container.getOverlay().remove(button);
                    }
 
                    @Override
                    public void onAnimationCancel(Animator arg0) {
                        container.getOverlay().remove(button);
                    }
                });
 
                anim.setDuration(2000);
 
                AnimatorSet set = new AnimatorSet();
                set.playTogether(anim, rotate);
                set.start();
            }
        });
 
        final Button button2 = (Button) findViewById(R.id.button2);
        button2.setOnClickListener(new OnClickListener() {
 
            @Override
            public void onClick(View arg0) {
                // Normal animation, we only see it when is animating in its original layout container.
                final ViewGroup container = (ViewGroup) button2.getParent().getParent();
                ObjectAnimator anim = ObjectAnimator.ofFloat(button2, "translationY", -container.getHeight());
                anim.setDuration(2000);
                anim.start();
            }
        });
 
        final Button button3 = (Button) findViewById(R.id.button3);
        button3.setOnClickListener(new OnClickListener() {
 
            @Override
            public void onClick(View arg0) {
                ObjectAnimator fadeOut = ObjectAnimator.ofFloat(button3, "alpha", 1f, 0f);
                fadeOut.setDuration(500);
 
                /* 
                 * Here we add our button to center layout's ViewGroupOverlay
                 * when first fade-out animation ends.
                 */
                final ViewGroup container = (ViewGroup) button2.getParent();
                final ObjectAnimator anim = ObjectAnimator.ofFloat(button3, "translationY", -container.getHeight() * 2);
                anim.setDuration(2000);
 
                anim.addListener(new AnimatorListener() {
 
                    @Override
                    public void onAnimationStart(Animator animation) { }
 
                    @Override
                    public void onAnimationRepeat(Animator animation) { }
 
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        container.getOverlay().remove(button3);
                    }
 
                    @Override
                    public void onAnimationCancel(Animator animation) {
                        container.getOverlay().remove(button3);
                    }
                });
 
                fadeOut.addListener(new AnimatorListener() {
 
                    @Override
                    public void onAnimationStart(Animator arg0) {
                    }
 
                    @Override
                    public void onAnimationRepeat(Animator arg0) {
                    }
 
                    @Override
                    public void onAnimationEnd(Animator arg0) {
                        container.getOverlay().add(button3);
                        button3.setAlpha(1f);
                        anim.start();
                    }
 
                    @Override
                    public void onAnimationCancel(Animator arg0) {
                        container.getOverlay().add(button3);
                        button3.setAlpha(1f);
                        anim.start();
                    }
                });
 
                fadeOut.start();
            }
        });
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.action_reset) { 
            viewsSetup();
        }
        return super.onOptionsItemSelected(item);
    }
 
}
package cat.lafosca.viewoverlaytest;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.widget.Button;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		viewsSetup();
	}

	private void viewsSetup() {
		setContentView(R.layout.activity_main);

		final Button button = (Button) findViewById(R.id.button);

		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// Our button is added to the parent of its parent, the most top-level layout
				final ViewGroup container = (ViewGroup) button.getParent().getParent();
				container.getOverlay().add(button);

				ObjectAnimator anim = ObjectAnimator.ofFloat(button, "translationY", container.getHeight());
				ObjectAnimator rotate = ObjectAnimator.ofFloat(button, "rotation", 0, 360);
				rotate.setRepeatCount(Animation.INFINITE);
				rotate.setRepeatMode(Animation.REVERSE);
				rotate.setDuration(350);

				/*
				 * Button needs to be removed after animation ending
				 * When we have added the view to the ViewOverlay, 
				 * it was removed from its original parent.
				 */
				anim.addListener(new AnimatorListener() {

					@Override
					public void onAnimationStart(Animator arg0) {
					}

					@Override
					public void onAnimationRepeat(Animator arg0) {
					}

					@Override
					public void onAnimationEnd(Animator arg0) {
						container.getOverlay().remove(button);
					}

					@Override
					public void onAnimationCancel(Animator arg0) {
						container.getOverlay().remove(button);
					}
				});

				anim.setDuration(2000);

				AnimatorSet set = new AnimatorSet();
				set.playTogether(anim, rotate);
				set.start();
			}
		});

		final Button button2 = (Button) findViewById(R.id.button2);
		button2.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// Normal animation, we only see it when is animating in its original layout container.
				final ViewGroup container = (ViewGroup) button2.getParent().getParent();
				ObjectAnimator anim = ObjectAnimator.ofFloat(button2, "translationY", -container.getHeight());
				anim.setDuration(2000);
				anim.start();
			}
		});

		final Button button3 = (Button) findViewById(R.id.button3);
		button3.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				ObjectAnimator fadeOut = ObjectAnimator.ofFloat(button3, "alpha", 1f, 0f);
				fadeOut.setDuration(500);

				/* 
				 * Here we add our button to center layout's ViewGroupOverlay
				 * when first fade-out animation ends.
				 */
				final ViewGroup container = (ViewGroup) button2.getParent();
				final ObjectAnimator anim = ObjectAnimator.ofFloat(button3, "translationY", -container.getHeight() * 2);
				anim.setDuration(2000);

				anim.addListener(new AnimatorListener() {

					@Override
					public void onAnimationStart(Animator animation) { }

					@Override
					public void onAnimationRepeat(Animator animation) { }

					@Override
					public void onAnimationEnd(Animator animation) {
						container.getOverlay().remove(button3);
					}

					@Override
					public void onAnimationCancel(Animator animation) {
						container.getOverlay().remove(button3);
					}
				});

				fadeOut.addListener(new AnimatorListener() {

					@Override
					public void onAnimationStart(Animator arg0) {
					}

					@Override
					public void onAnimationRepeat(Animator arg0) {
					}

					@Override
					public void onAnimationEnd(Animator arg0) {
						container.getOverlay().add(button3);
						button3.setAlpha(1f);
						anim.start();
					}

					@Override
					public void onAnimationCancel(Animator arg0) {
						container.getOverlay().add(button3);
						button3.setAlpha(1f);
						anim.start();
					}
				});

				fadeOut.start();
			}
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getItemId() == R.id.action_reset) { 
			viewsSetup();
		}
		return super.onOptionsItemSelected(item);
	}

}

完整代码下载:You can download and check our project from right here.

参照文章:http://www.lafosca.cat/viewoverlay-in-android/

给我留言

留言无头像?


×
腾讯微博