【问题标题】:How to implement a backstack when using the KitKat Transitions Framework使用 KitKat 过渡框架时如何实现 backstack
【发布时间】:2014-04-09 23:29:18
【问题描述】:

我在 Android 上使用新的 KitKat Transitions API。我使用两种布局创建了两个 Scene 对象。我在Fragment 中从Scene 1Scene 2 进行动画处理。当用户按下后退按钮时,我想自动回到之前的Scene

使用Transitions 时是否有某种内置的 backstack 机制,还是我必须自己滚动?

调用TransitionManager.go(scene1) 很容易,但我真的不想在所有具有Scene 动画的片段中实现onBackPressed() 侦听器。

【问题讨论】:

    标签: android android-animation android-4.4-kitkat android-transitions


    【解决方案1】:

    我最终推出了自己的解决方案。

    让您的 Activity 实现此功能

    public interface SceneBackstackHandler {
    
        public void addBackstackListener(BackstackListener listener);
    
        public void removeBackstackListener(BackstackListener listener);
    
        public void removeAllBackstackListeners();
    
        public interface BackstackListener {
            public boolean onBackPressed();
        }
    }
    

    活动

    private final Object mBackstackListenerLock = new Object();
    private List<BackstackListener> mBackstackListeners = new ArrayList<>();
    
    @Override
    public void onBackPressed() {
        synchronized (mBackstackListenerLock) {
            for (BackstackListener mBackstackListener : mBackstackListeners) {
                if (mBackstackListener.onBackPressed()) {
                    // handled by fragment
                    return;
                }
            }
            super.onBackPressed();
        }
    }
    
    @Override
    protected void onPause() {
        super.onPause();
        removeAllBackstackListeners();
    }
    
    @Override
    public void addBackstackListener(BackstackListener listener) {
        synchronized (mBackstackListenerLock) {
            mBackstackListeners.add(listener);
        }
    }
    
    @Override
    public void removeBackstackListener(BackstackListener listener) {
        synchronized (mBackstackListenerLock) {
            mBackstackListeners.remove(listener);
        }
    }
    
    @Override
    public void removeAllBackstackListeners() {
        synchronized (mBackstackListenerLock) {
            mBackstackListeners.clear();
        }
    }
    

    子片段:

    public class MySceneFragment extends Fragment
            implements SceneBackstackHandler.BackstackListener {
    
        private Scene mCurrentScene;
    
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            mBackstackHandler = (SceneBackstackHandler) activity;
            mBackstackHandler.addBackstackListener(this);
        }
    
        @Override
        public void onDetach() {
            super.onDetach();
            mBackstackHandler.removeBackstackListener(this);
        }
    
        @Override
        public boolean onBackPressed() {
            if (mCurrentScene != null && mCurrentScene.equals(mMyScene)) {
                removeMyScene();
                return true;
            }
            return false;
        }
    
        private void changeScene(Scene scene) {
            TransitionManager.go(scene);
            mCurrentScene = scene;
        }
    }
    

    【讨论】:

    • 如何存储 mCurrentScene?你是在 removeMyScene() 中使用 TM.go(scene) 还是只是调用 .exit()?
    • 我将该部分添加到示例中。 mCurrentSceneMySceneFragment 中的一个字段。我使用TransitionManager#go 来更改正在显示的场景。我从不“移除”一个场景,只是在它们之间移动。
    【解决方案2】:

    我使用Otto event bus 在我的ActivityFragments 之间进行通信。控制Activity 维护自己的自定义返回事件Stack,每个事件都包含一个返回动作Runnable,即按下返回按钮时应该采取什么动作。

    这种方法的优点是设计更加解耦,并且可以扩展更多片段。为了便于阅读,我在我的Fragment 中定义了 Otto 事件,在这里,但是这些可以很容易地移动到您项目的其他地方。

    这里有一些示例代码,让您了解它是如何完成的。

    片段

    片段通过 postingBackStackRequestEvent 向 Otto 事件总线发出信号,它打算抓住下一次后按,并提供一个 Runnable 动作,以便在事件从 Activity 弹出时执行。 s 自定义堆栈。当 Fragment 分离时,它会向总线发送 ClearBackStackEvent 以从 Activity 的自定义堆栈中删除 Fragment 的任何后退操作。

    public class MyFragment extends Fragment {
    
        private final String BACK_STACK_ID = "MY_FRAGMENT";
    
        ...
    
        public class BackStackRequestEvent {
            private Runnable action;
            private String id;
    
            public BackStackRequestEvent(Runnable action, String id) {
                this.action = action;
                this.id = id;
            }
    
            public void goBack() {
                action.run();
            }
    
            public String getId() {
                return id;
            }
        }
    
        public class ClearBackStackEvent {
            private String id;
    
            public ClearBackStackEvent(String id) {
                this.id = id;
            }
    
            public String getId() {
                return id;
            }
        }
    
        ...
    
        @Override
        public void onDetach() {
            super.onDetach();
            // Get your Otto singleton and notify Activity that this
            // Fragment's back actions are no longer needed
            // The Fragment lifecycle stage in which you do this might vary
            // based on your needs
            EventBus.getInstance().post(new ClearBackStackEvent(BACK_STACK_ID));
        }
    
        ...
    
        public void someChangeInFragment() {
            // Notify the Activity that we want to intercept the next onBackPressed
            EventBus.getInstance().post(new BackStackRequestEvent(new Runnable()
            {
                @Override
                public void run() {
                    // Reverse what we did
                    doBackAction();
                }
            }, BACK_STACK_ID)); // constant used later to remove items from Stack
        }
    }
    

    活动

    活动registers / unregisters 对我们上面在onStart()onStop() 中定义的事件感兴趣。当它收到一个新的BackStackRequestEvent 时,它会将它添加到它的自定义后台堆栈中。一旦调用了onBackPressed(),它就会弹出返回堆栈并使用BackStackRequestEvent.goBack() 调用返回操作,而BackStackRequestEvent.goBack() 又运行Fragment 的Runnable。如果堆栈上没有任何内容,则遵循正常的返回行为。

    当 Fragment 被分离时,Activity 会收到一个 ClearBackStackEvent 并从 Stack 中删除提供的 id 的所有项目。

    public class MyActivity extends Activity {
    
        private Stack<MyFragment.BackStackRequestEvent> customBackStack = new Stack<>();
    
        ...
    
        @Override
        protected void onStart() {
            super.onStart();
            EventBus.getInstance().register(this);
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            EventBus.getInstance().unregister(this);
        }
    
        @Subscribe // Annotation indicating that we want to intercept this Otto event
        public void backStackRequested(MyFragment.BackStackRequestEvent request) {
            customBackStack.push(request);
        }
    
        @Override
        public void onBackPressed() {
            if (customBackStack.empty()) {
                // No custom actions so default behaviour followed
                super.onBackPressed();
            }
            else {
                // Pop the custom action and call its goBack() action
                MyFragment.BackStackRequestEvent back = customBackStack.pop();
                back.goBack();
            }
        }
    
        @Subscribe
        public void clearBackStackRequested(MyFragment.ClearBackStackEvent request) {
            String id = request.getId();
            for (MyFragment.BackStackRequestEvent backItem : customBackStack) {
                if (backItem.getId().contentEquals(id)) {
                    customBackStack.remove(backItem);
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-10-17
      • 2011-08-12
      • 2019-04-12
      • 2020-04-21
      • 2012-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多