Android Activity 轉場動畫
阿新 • • 發佈:2018-12-19
序言
好久沒有寫部落格了,真是越來越懶了,還是要改變!今天學習了很有可能會應用到工作中的動畫效果。
效果圖
實現思路
LoginActivity 通過轉場動畫跳轉到 MainActivity :
- 在 LoginActivity 中確定動畫的開始位置座標,並通過 intent 傳遞給 MainActivity。
- MainActivity 拿到動畫起始位置執行動畫,如果需要 finish 掉 LoginActivity ,在 MainActivity 動畫執行結束時 finish 掉。
- MainActivity 的 window 背景需要設定為透明,並且 根佈局 background 需要設定為非透明的。
- 動畫執行結束銷燬 LoginActivity ,採用本地廣播方式。
實現程式碼
LoginActivity :
activity_login.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@mipmap/login_bg" tools:context=".MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="60dp" android:onClick="click" android:text="login" /> </RelativeLayout>
LoginActivity.java
public class LoginActivity extends AppCompatActivity { public static final String POSITION_X = "position_x"; public static final String POSITION_Y = "position_y"; private BroadcastReceiver receiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); registerBroadcast(); } private void registerBroadcast() { receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (MainActivity.ACTION_CLOSE_LOGIN.equals(action)) { finish(); } } }; IntentFilter filter = new IntentFilter(MainActivity.ACTION_CLOSE_LOGIN); LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter); } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) public void click(View view) { ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(this, view, "transtion"); // 起始位置 int startX = (int) (view.getX() + view.getWidth() / 2); int startY = (int) (view.getY() + view.getHeight() / 2); Intent intent = new Intent(this, MainActivity.class); intent.putExtra(POSITION_X, startX); intent.putExtra(POSITION_Y, startY); startActivity(intent, options.toBundle()); // 要等 MainActivity動畫執行結束才能 finish 掉 // finish(); } @Override protected void onDestroy() { super.onDestroy(); if (receiver != null) { LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver); } } }
MainActivity 佈局就兩張圖片,佈局程式碼省略。
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static final String ACTION_CLOSE_LOGIN = "com.xing.activityanim.CLOSE_LOGIN";
private LinearLayout rootLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rootLayout = findViewById(R.id.rl_main_root);
Intent intent = getIntent();
final int startX = intent.getIntExtra(LoginActivity.POSITION_X, 0);
final int startY = intent.getIntExtra(LoginActivity.POSITION_Y, 0);
// 系統版本在 5.0 以上,執行轉場動畫
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
ViewTreeObserver viewTreeObserver = rootLayout.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
revealActivity(startX, startY);
// viewTreeObserver.removeOnGlobalLayoutListener(this); // 這樣寫會報錯
rootLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
} else {
}
}
private void revealActivity(int x, int y) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
float finalRadius = Math.max(rootLayout.getWidth(), rootLayout.getHeight());
Animator circularReveal = ViewAnimationUtils.createCircularReveal(rootLayout, x, y, 0, finalRadius);
circularReveal.setDuration(600);
circularReveal.setInterpolator(new LinearInterpolator());
circularReveal.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
// 傳送關閉 LoginActivity 廣播
sendCloseBroadcast();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
circularReveal.start();
}
rootLayout.setVisibility(View.VISIBLE);
}
private void sendCloseBroadcast() {
Intent intent = new Intent(ACTION_CLOSE_LOGIN);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
其中 MainActivity 配置了透明主題
Androidmanifest.xml
<activity
android:name=".MainActivity"
android:theme="@style/TransparentTheme" />
styles.xml
<style name="TransparentTheme" parent="AppTheme">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>