我在 Android 上使用新的 KitKat转换API。我Scene
使用两种布局创建了两个对象。我从Scene 1
一个. 当用户按下后退按钮时,我想自动回到上一个。Scene 2
Fragment
Scene
使用时是否有某种内置的 backstack 机制Transitions
,还是我必须自己滚动?
调用很容易TransitionManager.go(scene1)
,但我真的不想onBackPressed()
在所有有Scene
动画的片段中实现监听器。
我在 Android 上使用新的 KitKat转换API。我Scene
使用两种布局创建了两个对象。我从Scene 1
一个. 当用户按下后退按钮时,我想自动回到上一个。Scene 2
Fragment
Scene
使用时是否有某种内置的 backstack 机制Transitions
,还是我必须自己滚动?
调用很容易TransitionManager.go(scene1)
,但我真的不想onBackPressed()
在所有有Scene
动画的片段中实现监听器。
我最终推出了自己的解决方案。
让你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;
}
}
我使用Otto 事件总线在 myActivity
和Fragment
s 之间进行通信。控件Activity
维护自己Stack
的自定义返回事件,每个事件都包含一个返回动作Runnable
,即按下返回按钮时应该采取什么动作。
这种方法的优点是稍微解耦的设计,并且应该使用更多的片段进行扩展。为了便于阅读,我在我的Fragment
, 中定义了 Otto 事件,但是这些可以很容易地移动到您项目的其他地方。
这是一些示例代码,可让您了解它是如何完成的。
Fragment 通过将a发布BackStackRequestEvent
到 Otto 事件总线并提供要在事件从的自定义堆栈Runnable
中弹出时执行的操作来表明其意图掌握下一次后按。Activity
当 Fragment 分离时,它会向ClearBackStackEvent
总线发送 a 以Fragment
从 Activity 的自定义堆栈中删除任何 的后退操作。
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
}
}
该活动注册/取消注册onStart()
它对我们上面在和中定义的事件的兴趣onStop()
。当它收到一个新的BackStackRequestEvent
时,它会将它添加到它的自定义后台堆栈中。一旦onBackPressed()
被调用,它就会弹出返回堆栈并调用返回操作,使用BackStackRequestEvent.goBack()
该操作依次运行 Fragment 的Runnable
. 如果堆栈上没有任何内容,则遵循正常的返回行为。
当 Fragment 分离时,Activity 收到 aClearBackStackEvent
并id
从 Stack 中删除所有提供的项目。
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);
}
}
}
}