我在Android上使用新的KitKat Transitions API。我使用两个布局创建了两个Scene
个对象。我在Scene 1
内从Scene 2
动态设为Fragment
。当用户按下后退按钮时,我想自动回到之前的Scene
。
使用Transitions
时是否存在某种内置的后台堆叠机制,或者我是否需要自己滚动?
调用TransitionManager.go(scene1)
很容易,但我真的不想在所有具有onBackPressed()
动画的片段中实现Scene
侦听器。
答案 0 :(得分: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;
}
}
答案 1 :(得分:1)
我使用Otto event bus在Activity
和Fragment
之间进行通信。控制Activity
维护自己的Stack
自定义后退事件,每个事件都包含后退操作Runnable
,即按下后退按钮时应采取的操作。
这种方法的优点是稍微更加分离的设计,并且应该扩展更多的碎片。为了便于阅读,我在此处Fragment
中定义了Otto事件,但这些事件可以很容易地移到项目的其他位置。
这里有一些示例代码,可以让您了解它是如何完成的。
Fragment表示有意通过posting BackStackRequestEvent
向Otto事件总线进行下一次后退,并提供Runnable
动作,以便在弹出事件时执行关闭Activity
的自定义堆栈。分离片段后,它会向总线发送ClearBackStackEvent
,以从活动的自定义堆栈中删除任何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()
调用后退操作,后者又会运行片段Runnable
。如果堆栈中没有任何内容,则遵循正常的后退行为。
分离片段时,活动会收到ClearBackStackEvent
,并从堆栈中删除所提供的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);
}
}
}
}