From 94ed30b0550f29b58774fcd28aa98d28562be985 Mon Sep 17 00:00:00 2001 From: Mike Harris Date: Sat, 7 Oct 2017 23:52:13 -0700 Subject: [PATCH] Use the fragment backstack properly, and use fragment animations. Make the MenuFragment added and removed by fragment transactions only, instead of being initially present in the XML. This fixes a glitch where it doesn't animate correctly the first time it's used. --- .../activities/EmulationActivity.java | 115 ++++++------------ .../dolphinemu/fragments/MenuFragment.java | 25 ++-- .../dolphinemu/utils/Animations.java | 42 ------- .../res/animator/menu_slide_in_from_left.xml | 20 +++ ...de_in.xml => menu_slide_in_from_right.xml} | 2 +- .../res/animator/menu_slide_out_to_left.xml | 21 ++++ ...de_out.xml => menu_slide_out_to_right.xml} | 6 +- .../layout-television/activity_emulation.xml | 16 +-- 8 files changed, 106 insertions(+), 141 deletions(-) create mode 100644 Source/Android/app/src/main/res/animator/menu_slide_in_from_left.xml rename Source/Android/app/src/main/res/animator/{menu_slide_in.xml => menu_slide_in_from_right.xml} (93%) create mode 100644 Source/Android/app/src/main/res/animator/menu_slide_out_to_left.xml rename Source/Android/app/src/main/res/animator/{menu_slide_out.xml => menu_slide_out_to_right.xml} (87%) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 14d0e2c9be..f02a0e3b3b 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -14,6 +14,7 @@ import android.preference.PreferenceManager; import android.support.annotation.IntDef; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; import android.support.v7.app.AppCompatActivity; import android.util.SparseIntArray; import android.view.InputDevice; @@ -24,7 +25,6 @@ import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; @@ -42,7 +42,6 @@ import org.dolphinemu.dolphinemu.ui.platform.Platform; import org.dolphinemu.dolphinemu.utils.Animations; import org.dolphinemu.dolphinemu.utils.Java_GCAdapter; import org.dolphinemu.dolphinemu.utils.Java_WiimoteAdapter; -import org.dolphinemu.dolphinemu.utils.Log; import java.lang.annotation.Retention; import java.util.List; @@ -51,13 +50,12 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; public final class EmulationActivity extends AppCompatActivity { - private static final String FRAGMENT_SUBMENU_TAG = "submenu"; + private static final String BACKSTACK_NAME_MENU = "menu"; + private static final String BACKSTACK_NAME_SUBMENU = "submenu"; private View mDecorView; private ImageView mImageView; private EmulationFragment mEmulationFragment; - private LinearLayout mMenuLayout; - private SharedPreferences mPreferences; // So that MainActivity knows which view to invalidate before the return animation. @@ -66,7 +64,6 @@ public final class EmulationActivity extends AppCompatActivity private boolean mDeviceHasTouchScreen; private boolean mSystemUiVisible; private boolean mMenuVisible; - private boolean mSubMenuVisible = false; private static boolean mIsGameCubeGame; @@ -221,7 +218,6 @@ public final class EmulationActivity extends AppCompatActivity setContentView(R.layout.activity_emulation); mImageView = (ImageView) findViewById(R.id.image_screenshot); - mMenuLayout = (LinearLayout) findViewById(R.id.layout_ingame_menu); mEmulationFragment = (EmulationFragment) getSupportFragmentManager() .findFragmentById(R.id.fragment_emulation); @@ -280,16 +276,6 @@ public final class EmulationActivity extends AppCompatActivity { setTitle(mSelectedTitle); } - else - { - MenuFragment menuFragment = (MenuFragment) getSupportFragmentManager() - .findFragmentById(R.id.fragment_menu); - - if (menuFragment != null) - { - menuFragment.setTitleText(mSelectedTitle); - } - } mPreferences = PreferenceManager.getDefaultSharedPreferences(this); @@ -333,11 +319,9 @@ public final class EmulationActivity extends AppCompatActivity { if (!mDeviceHasTouchScreen) { - if (mSubMenuVisible) - { - removeSubMenu(); - } - else + boolean popResult = getSupportFragmentManager().popBackStackImmediate( + BACKSTACK_NAME_SUBMENU, FragmentManager.POP_BACK_STACK_INCLUSIVE); + if (!popResult) { toggleMenu(); } @@ -347,31 +331,28 @@ public final class EmulationActivity extends AppCompatActivity mEmulationFragment.stopEmulation(); exitWithAnimation(); } + } private void toggleMenu() { - if (mMenuVisible) - { - mMenuVisible = false; + boolean result = getSupportFragmentManager().popBackStackImmediate( + BACKSTACK_NAME_MENU, FragmentManager.POP_BACK_STACK_INCLUSIVE); + mMenuVisible = false; - Animations.fadeViewOutToLeft(mMenuLayout) - .withEndAction(new Runnable() - { - @Override - public void run() - { - if (mMenuVisible) - { - mMenuLayout.setVisibility(View.GONE); - } - } - }); - } - else - { + if (!result) { + // Removing the menu failed, so that means it wasn't visible. Add it. + Fragment fragment = MenuFragment.newInstance(mSelectedTitle); + getSupportFragmentManager().beginTransaction() + .setCustomAnimations( + R.animator.menu_slide_in_from_left, + R.animator.menu_slide_out_to_left, + R.animator.menu_slide_in_from_left, + R.animator.menu_slide_out_to_left) + .add(R.id.frame_menu, fragment) + .addToBackStack(BACKSTACK_NAME_MENU) + .commit(); mMenuVisible = true; - Animations.fadeViewInFromLeft(mMenuLayout); } } @@ -422,7 +403,7 @@ public final class EmulationActivity extends AppCompatActivity finishAfterTransition(); } }; - + @Override public boolean onCreateOptionsMenu(Menu menu) { @@ -496,14 +477,14 @@ public final class EmulationActivity extends AppCompatActivity case MENU_ACTION_SAVE_ROOT: if (!mDeviceHasTouchScreen) { - showMenu(SaveLoadStateFragment.SaveOrLoad.SAVE); + showSubMenu(SaveLoadStateFragment.SaveOrLoad.SAVE); } return; case MENU_ACTION_LOAD_ROOT: if (!mDeviceHasTouchScreen) { - showMenu(SaveLoadStateFragment.SaveOrLoad.LOAD); + showSubMenu(SaveLoadStateFragment.SaveOrLoad.LOAD); } return; @@ -817,44 +798,22 @@ public final class EmulationActivity extends AppCompatActivity hideSystemUiAfterDelay(); } - private void showMenu(SaveLoadStateFragment.SaveOrLoad saveOrLoad) + private void showSubMenu(SaveLoadStateFragment.SaveOrLoad saveOrLoad) { + // Get rid of any visible submenu + getSupportFragmentManager().popBackStack( + BACKSTACK_NAME_SUBMENU, FragmentManager.POP_BACK_STACK_INCLUSIVE); + Fragment fragment = SaveLoadStateFragment.newInstance(saveOrLoad); getSupportFragmentManager().beginTransaction() - .setCustomAnimations(R.animator.menu_slide_in, R.animator.menu_slide_out) - .replace(R.id.frame_submenu, fragment, FRAGMENT_SUBMENU_TAG) + .setCustomAnimations( + R.animator.menu_slide_in_from_right, + R.animator.menu_slide_out_to_right, + R.animator.menu_slide_in_from_right, + R.animator.menu_slide_out_to_right) + .replace(R.id.frame_submenu, fragment) + .addToBackStack(BACKSTACK_NAME_SUBMENU) .commit(); - mSubMenuVisible = true; - } - - private void removeSubMenu() - { - final Fragment fragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_SUBMENU_TAG); - - if (fragment != null) - { - // When removing a fragment without replacement, its animation must be done - // manually beforehand. - Animations.fadeViewOutToRight(fragment.getView()) - .withEndAction(new Runnable() - { - @Override - public void run() - { - if (mMenuVisible) - { - getSupportFragmentManager().beginTransaction() - .remove(fragment) - .commit(); - } - } - }); - } - else - { - Log.error("[EmulationActivity] Fragment not found, can't remove."); - } - mSubMenuVisible = false; } public String getSelectedTitle() diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java index 2b718ac58d..34898e8f8b 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/MenuFragment.java @@ -16,7 +16,7 @@ import org.dolphinemu.dolphinemu.activities.EmulationActivity; public final class MenuFragment extends Fragment implements View.OnClickListener { - private TextView mTitleText; + private static final String KEY_TITLE = "title"; private static SparseIntArray buttonsActionsMap = new SparseIntArray(); static { buttonsActionsMap.append(R.id.menu_take_screenshot, EmulationActivity.MENU_ACTION_TAKE_SCREENSHOT); @@ -28,6 +28,17 @@ public final class MenuFragment extends Fragment implements View.OnClickListener buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT); } + public static MenuFragment newInstance(String title) + { + MenuFragment fragment = new MenuFragment(); + + Bundle arguments = new Bundle(); + arguments.putSerializable(KEY_TITLE, title); + fragment.setArguments(arguments); + + return fragment; + } + @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) @@ -42,7 +53,12 @@ public final class MenuFragment extends Fragment implements View.OnClickListener button.setOnClickListener(this); } - mTitleText = (TextView) rootView.findViewById(R.id.text_game_title); + TextView titleText = rootView.findViewById(R.id.text_game_title); + String title = getArguments().getString(KEY_TITLE); + if (title != null) + { + titleText.setText(title); + } return rootView; } @@ -57,9 +73,4 @@ public final class MenuFragment extends Fragment implements View.OnClickListener ((EmulationActivity) getActivity()).handleMenuAction(action); } } - - public void setTitleText(String title) - { - mTitleText.setText(title); - } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Animations.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Animations.java index cff0dcb363..777a921493 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Animations.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Animations.java @@ -2,55 +2,13 @@ package org.dolphinemu.dolphinemu.utils; import android.view.View; import android.view.ViewPropertyAnimator; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; public final class Animations { - private static final Interpolator DECELERATOR = new DecelerateInterpolator(); - private static final Interpolator ACCELERATOR = new AccelerateInterpolator(); - private Animations() { } - public static ViewPropertyAnimator fadeViewOutToRight(View view) - { - return view.animate() - .withLayer() - .setDuration(200) - .setInterpolator(ACCELERATOR) - .alpha(0.0f) - .translationX(view.getWidth()); - } - - public static ViewPropertyAnimator fadeViewOutToLeft(View view) - { - return view.animate() - .withLayer() - .setDuration(200) - .setInterpolator(ACCELERATOR) - .alpha(0.0f) - .translationX(-view.getWidth()); - } - - public static ViewPropertyAnimator fadeViewInFromLeft(View view) - { - - view.setVisibility(View.VISIBLE); - - view.setTranslationX(-view.getWidth()); - view.setAlpha(0.0f); - - return view.animate() - .withLayer() - .setDuration(300) - .setInterpolator(DECELERATOR) - .alpha(1.0f) - .translationX(0.0f); - } - public static ViewPropertyAnimator fadeViewIn(View view) { view.setVisibility(View.VISIBLE); diff --git a/Source/Android/app/src/main/res/animator/menu_slide_in_from_left.xml b/Source/Android/app/src/main/res/animator/menu_slide_in_from_left.xml new file mode 100644 index 0000000000..4612aee134 --- /dev/null +++ b/Source/Android/app/src/main/res/animator/menu_slide_in_from_left.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/Source/Android/app/src/main/res/animator/menu_slide_in.xml b/Source/Android/app/src/main/res/animator/menu_slide_in_from_right.xml similarity index 93% rename from Source/Android/app/src/main/res/animator/menu_slide_in.xml rename to Source/Android/app/src/main/res/animator/menu_slide_in_from_right.xml index fff198cb47..3f1495c757 100644 --- a/Source/Android/app/src/main/res/animator/menu_slide_in.xml +++ b/Source/Android/app/src/main/res/animator/menu_slide_in_from_right.xml @@ -4,7 +4,7 @@ diff --git a/Source/Android/app/src/main/res/animator/menu_slide_out_to_left.xml b/Source/Android/app/src/main/res/animator/menu_slide_out_to_left.xml new file mode 100644 index 0000000000..0e21cf8489 --- /dev/null +++ b/Source/Android/app/src/main/res/animator/menu_slide_out_to_left.xml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/Source/Android/app/src/main/res/animator/menu_slide_out.xml b/Source/Android/app/src/main/res/animator/menu_slide_out_to_right.xml similarity index 87% rename from Source/Android/app/src/main/res/animator/menu_slide_out.xml rename to Source/Android/app/src/main/res/animator/menu_slide_out_to_right.xml index 88f300280a..78edf872cf 100644 --- a/Source/Android/app/src/main/res/animator/menu_slide_out.xml +++ b/Source/Android/app/src/main/res/animator/menu_slide_out_to_right.xml @@ -6,9 +6,9 @@ android:propertyName="translationX" android:valueType="floatType" android:valueFrom="0" - android:valueTo="1280" + android:valueTo="1280dp" android:interpolator="@android:interpolator/decelerate_quad" - android:duration="300"/> + android:duration="200"/> + android:duration="200"/> \ No newline at end of file diff --git a/Source/Android/app/src/main/res/layout-television/activity_emulation.xml b/Source/Android/app/src/main/res/layout-television/activity_emulation.xml index ad67bcb05e..3009f40e84 100644 --- a/Source/Android/app/src/main/res/layout-television/activity_emulation.xml +++ b/Source/Android/app/src/main/res/layout-television/activity_emulation.xml @@ -21,28 +21,24 @@ android:id="@+id/image_screenshot" android:transitionName="image_game_screenshot"/> + + android:orientation="horizontal"> - + android:layout_weight=".75"/>