https://developer.Android.com/training/material/animations.html
ViewAnimationUtils.createCircularReveal()
メソッドを使用すると、クリッピングサークルをアニメートして、ビューを表示または非表示にすることができます。この効果を使用して、以前は見えなかったビューを表示するには:
// previously invisible view View myView = findViewById(R.id.my_view); // get the center for the clipping circle int cx = (myView.getLeft() + myView.getRight()) / 2; int cy = (myView.getTop() + myView.getBottom()) / 2; // get the final radius for the clipping circle int finalRadius = Math.max(myView.getWidth(), myView.getHeight()); // create the animator for this view (the start radius is zero) Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius); // make the view visible and start the animation myView.setVisibility(View.VISIBLE); anim.start();
これは、ビューを明らかにするためのものです。これを使用して、共有要素なしでアクティビティ全体を循環的に表示するにはどうすればよいですか?
具体的には、ツールバーの検索アクションボタンからsearchActivityが循環的に表示されるようにします。
結果なしで半日ソリューションを探した後、私は独自の実装を思いつきました。ルートレイアウトが一致する透明なアクティビティを使用しています。ルートレイアウトは、createCircularReveal()
で表示できるビューです。
私のコードは次のようになります。
styles.xmlのテーマ定義
<style name="Theme.Transparent" parent="Theme.AppCompat.Light.NoActionBar">
<item name="Android:windowIsTranslucent">true</item>
<item name="Android:statusBarColor">@Android:color/transparent</item>
<item name="Android:windowBackground">@Android:color/transparent</item>
</style>
AndroidManifest.xmlのアクティビティ定義
<activity
Android:name=".ui.CircularRevealActivity"
Android:theme="@style/Theme.Transparent"
Android:launchMode="singleTask"
/>
次に、アクティビティのレイアウトを宣言しました(NavDrawerを使用できるように、DrawerLayoutを選択しました。すべてのレイアウトがここで機能するはずです)。
<Android.support.v4.widget.DrawerLayout
Android:id="@+id/drawer_layout"
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
>
<FrameLayout
Android:id="@+id/root_layout"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:background="@color/honey_melon"
>
<!-- Insert your actual layout here -->
</FrameLayout>
</Android.support.v4.widget.DrawerLayout>
重要なのは、ID root_layout
のFrameLayoutです。このビューはアクティビティで明らかにされます。
最後にCircularRevealActivity
を実装し、onCreate()
を上書きしました:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
overridePendingTransition(R.anim.do_not_move, R.anim.do_not_move);
setContentView(R.layout.activity_reveal_circular);
if (savedInstanceState == null) {
rootLayout.setVisibility(View.INVISIBLE);
ViewTreeObserver viewTreeObserver = rootLayout.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
circularRevealActivity();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
rootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
rootLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});
}
}
}
アニメーションのためにビューを描画する必要があるため、circularRevealActivity()
をOnGlobalLayoutListener
に入れることが重要でした。
circularRevealActivity()
はIshaanの提案のように見えます:
private void circularRevealActivity() {
int cx = rootLayout.getWidth() / 2;
int cy = rootLayout.getHeight() / 2;
float finalRadius = Math.max(rootLayout.getWidth(), rootLayout.getHeight());
// create the animator for this view (the start radius is zero)
Animator circularReveal = ViewAnimationUtils.createCircularReveal(rootLayout, cx, cy, 0, finalRadius);
circularReveal.setDuration(1000);
// make the view visible and start the animation
rootLayout.setVisibility(View.VISIBLE);
circularReveal.start();
}
編集1
R.anim.do_not_move
の定義が追加されました。ただし、デザインでアクティビティのデフォルトの遷移を指定していない場合は、その行がなくても機能するはずです。お知らせ下さい
R.anim.do_not_move:
<set xmlns:Android="http://schemas.Android.com/apk/res/Android">
<translate
Android:fromYDelta="0"
Android:toYDelta="0"
Android:duration="@Android:integer/config_mediumAnimTime"
/>
</set>
CircularReveal
アニメーションを逆にするには、startRadius
とendRadius
引数を入れ替えます。また、AnimatorListener
をセットアップする必要があり、onAnimationEnd()
コールバックメソッドでfinishAfterTransition()
を呼び出すことができます。これは、up navigation
を押すか、back button
をクリックした場合に使用します。
退出アクティビティの循環表示を元に戻す場合は、onBackPressed()に次の変更を加えます。
@Override
public void onBackPressed() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
int cx = rootLayout.getWidth();
int cy = 0;
float finalRadius = Math.max(rootLayout.getWidth(), rootLayout.getHeight());
Animator circularReveal = ViewAnimationUtils.createCircularReveal(rootLayout, cx, cy, finalRadius, 0);
circularReveal.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
rootLayout.setVisibility(View.INVISIBLE);
finish();
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
circularReveal.setDuration(400);
circularReveal.start();
}else{
super.onBackPressed();
}
}
ActivityOptionsCompat.makeClipRevealAnimation
を使用できると思います。
[ https://developer.Android.com/reference/Android/support/v4/app/ActivityOptionsCompat.html#makeClipRevealAnimation(Android.view.View 、int、int、int、int)]( https://developer.Android.com/reference/Android/support/v4/app/ActivityOptionsCompat.html#makeClipRevealAnimation(Android.view.View 、int、int、int、int))
サークルビューを描画する必要があります。その後、アニメーションを作成する必要があります。
サークルビューの作成:
public class Circle extends View {
private static final int START_ANGLE_POINT = 90;
private final Paint paint;
private final RectF rect;
private float angle;
public Circle(Context context, AttributeSet attrs) {
super(context, attrs);
final int strokeWidth = 40;
Paint = new Paint();
Paint.setAntiAlias(true);
Paint.setStyle(Paint.Style.STROKE);
Paint.setStrokeWidth(strokeWidth);
//Circle color
Paint.setColor(Color.RED);
//size 200x200 example
rect = new RectF(strokeWidth, strokeWidth, 200 + strokeWidth, 200 + strokeWidth);
//Initial Angle (optional, it can be zero)
angle = 120;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(rect, START_ANGLE_POINT, angle, false, Paint);
}
public float getAngle() {
return angle;
}
public void setAngle(float angle) {
this.angle = angle;
}
}
新しい角度を設定するアニメーションクラスを作成します。
public class CircleAngleAnimation extends Animation {
private Circle circle;
private float oldAngle;
private float newAngle;
public CircleAngleAnimation(Circle circle, int newAngle) {
this.oldAngle = circle.getAngle();
this.newAngle = newAngle;
this.circle = circle;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation transformation) {
float angle = oldAngle + ((newAngle - oldAngle) * interpolatedTime);
circle.setAngle(angle);
circle.requestLayout();
}
}
レイアウトに円を入れます。
<com.package.Circle
Android:id="@+id/circle"
Android:layout_width="300dp"
Android:layout_height="300dp" />
そして最後にアニメーションを開始します:
Circle circle = (Circle) findViewById(R.id.circle);
CircleAngleAnimation animation = new CircleAngleAnimation(circle, 240);
animation.setDuration(1000);
circle.startAnimation(animation);