在主/细节片段中使用ActionBar Up导航

时间:2013-01-23 03:36:03

标签: android android-actionbar

我有一个主/详细布局的应用程序(1个活动,1个ListView片段和1个细节片段)。当用户单击ListView中的项目时,片段事务会在右窗格中实例化一个详细信息片段,其中包含与该项目对应的信息。当显示细节片段时,我隐藏了初始操作栏按钮/项目,并显示3个新的AB项目(完成/删除/取消)。用户可以通过按后退按钮或按下3 AB项之一来清理右窗格并返回初始UI状态。

我遇到的问题是当用户选择应用程序的主页图标(即“向上导航”)时,活动会重新加载(即表示活动正在启动的动画可以看作是动作栏和UI已被重绘)。只有在按下应用程序主页图标时才会出现此问题。如果用户按下后退按钮或取消/完成/删除操作栏按钮,则只需从右窗格中删除片段,UI将返回初始状态,而不会“重新加载”。

活动的XML布局如下(在LinearLayout内;美化隐藏该行):     

<fragment class="*.*.*.ListFragment"
        android:id="@+id/titles" android:layout_weight="1"
        android:layout_width="0px"
        android:layout_height="match_parent" />

<FrameLayout android:id="@+id/details" android:layout_weight="2"
        android:layout_width="0px"
        android:layout_height="match_parent" />

DetailsFragement在其onCreate方法中有actionBar.setDisplayHomeAsUpEnabled语句:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);


    ActionBar actionBar = getSherlockActivity().getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);

}

对于ListView片段和Detail片段,onCreateOptionsMenu()和onOptionsItemSelected()方法都在片段中实现。在详细信息片段的代码下面:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.edit_menu, menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    // some variable statements...

    switch (item.getItemId()) {
        case android.R.id.home:
            //Toast.makeText(getSherlockActivity(), "Tapped home", Toast.LENGTH_SHORT).show();
            onHomeSelectedListener.onHomeSelected();
            return true;

        case R.id.menu_edit_item_done:
            editedTask.setTitle(editedTaskTitle);
            onTaskEditedListener.onTaskEdited(editedTask, UPDATE_TASK, true);
            return true;

        default:
            return super.onOptionsItemSelected(item);

    }
}

在主机活动中,我实现了onHomeSelectedListner来处理app home图标按下(即“向上导航”:

public void onHomeSelected(){

    FragmentManager manager = getSupportFragmentManager();
    FragmentTransaction ft = manager.beginTransaction();
    TaskFragment taskFragment = (TaskFragment)getSupportFragmentManager().findFragmentById(R.id.details);
    ft.remove(taskFragment);
    ft.commit();
    manager.popBackStack();

}

负责处理所有其他操作栏按钮(即完成/删除/取消)的活动的监听器是onTaskEditedListener,除了处理某些数据的其他代码之外,它具有上面显示的相同片段事务。

更新(1/24) 基于tyczj和straya反馈,我将log语句放在onCreate(),onResume(),onPause()的活动中,以确定onHomeSelected和onTaskEdited监听器之间的差异。我能够确认在“向上导航”事件(即onHomeSelected)onPause()期间,调用onCreate()和onResume()。而在onTaskEdited调用期间(即后退按钮或完成/删除/取消按下),这些事件都不会被调用。

更新(1/25) 根据Mark Murphy的建议,我在“case android.R.id.home”语句中注释了onHomeSelected方法调用,只是为了看看Activity会做什么。我们的想法是应用程序什么都不做,因为没有声明。事实证明并非如此。即使没有调用侦听器方法(即删除片段),也会重新启动活动,并从片段容器中删除详细信息片段。

更新(2/28) 我通过禁用窗口动画(我在自己的答案中突出显示)暂时解决了我的主要活动重新启动的事实。但是,通过进一步测试,我发现了一个错误。感谢Wolfram Rittmeyer的示例代码,我能够找出在上导航期间我的活动重启(主/详细单一布局)的真正原因: 1)虽然我正在使用这个“onHomeSelectedListener”来正确地从backstack中删除片段,但我仍然在ListView片段的onOptionsItemSelected中创建了一些残余代码,这些代码创建了一个新的意图来启动托管活动。这就是为什么按下应用程序的主页图标重新启动活动。 2)在我的最终实现中(在我自己的答案中显示),我摆脱了活动中的onHomeSelectedListener并替换了ListView的onOptionsItemSelected中的startActivity意图(即违规代码),以使用最初在onHomeSelectedListener中的片段删除+ popBackStack代码。

4 个答案:

答案 0 :(得分:8)

经过大量的研究和探索,结果证明我的活动在主导/详细配置的“向上导航”期间重新启动的唯一原因是因为我在ListView片段的onOptionsItemSelected中留下了一些代码,这些代码正在创建一个启动主要的意图活动以及其他地方的完整片段事务代码。下面是最后的实现,我通过它“导航”在手机(多个活动)和平板电脑(单个活动/多窗格)配置上正常工作。感谢Wolfram Rittmeyer在他的代码中提供了几个提示(评论部分中的链接),这有助于我查明我的问题!

主要活动:托管片段并执行其他特定于应用的操作

ListView片段:处理表格配置中的“向上导航”

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            if(mDualPane){
                FragmentManager manager = getSherlockActivity().getSupportFragmentManager();
                FragmentTransaction ft = manager.beginTransaction();
                DetailFragment detailFragment = (DetailFragment)manager.findFragmentById(R.id.details);
                ft.remove(detailFragment);
                ft.commit();
                manager.popBackStack();
                getSherlockActivity().getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                getSherlockActivity().getSupportActionBar().setHomeButtonEnabled(false);
            }
            return true;

        // Other case statements...

        default:
            return super.onOptionsItemSelected(item);
    }
}

详细信息片段:处理手机配置中的导航

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);

    // Sets "up navigation" for both phone/tablet configurations
    ActionBar actionBar = getSherlockActivity().getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()) {
        case android.R.id.home:
            if(!mDualPane){
                Intent parentActivityIntent = new Intent(getSherlockActivity(), MainActivity.class);
                parentActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(parentActivityIntent);
                getSherlockActivity().finish();
            }
            return true;

        // Other case statements...

        default:
            return super.onOptionsItemSelected(item);
    }

}

答案 1 :(得分:3)

如果查看Navigation Design Pattern,您会看到在主页按钮被点击时您想要返回到开始活动。

所以说你有两个活动叫他们A1A2。点击A1中的某些内容即可转到A2。如果用户点击主页按钮,你应该将它们返回到A1,清除所有内容,直到这样的活动

Intent intent = new Intent(this, A1.class);  
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

这是Intent.FLAG_ACTIVITY_CLEAR_TOP标志

的标志
  

如果已设置,并且正在启动的活动已在当前任务中运行,则不会启动该活动的新实例,而是将关闭其上的所有其他活动,并将此Intent传递给(现在在最前面)作为新意图的旧活动。

     

例如,考虑一个由活动组成的任务:A,B,C,D。如果D调用带有解析为活动B组件的Intent的startActivity(),那么C和D将完成并且B接收给定的Intent,导致堆栈现在为:A,B。

     

上面示例中当前运行的活动B实例将在其onNewIntent()方法中接收您从此处开始的新意图,或者本身已完成并使用新意图重新启动。如果它已将其启动模式声明为“多个”(默认值)并且您没有在同一意图中设置FLAG_ACTIVITY_SINGLE_TOP,那么它将被完成并重新创建;对于所有其他启动模式或者如果设置了FLAG_ACTIVITY_SINGLE_TOP,则此Intent将被传递到当前实例的onNewIntent()。

     

此启动模式也可以与FLAG_ACTIVITY_NEW_TASK结合使用:如果用于启动任务的根活动,它会将该任务的任何当前运行的实例带到前台,然后将其清除到其根目录州。这在从通知管理器启动活动时尤其有用。

答案 2 :(得分:0)

不要:中断然后返回super.onOptionsItemSelected(item),而不仅仅是:return true;

更新:

所以你说这个活动是&#34;重新启动&#34;根据您在Views中看到的内容,但是您可以通过使用各种生命周期方法中的日志记录来确认Activity(和Fragments)可能会发生什么或不发生什么?这样,在进行诊断之前,您可以确定当前(错误)行为是什么。

更新:

好的,确定行为很好:) 现在关于你的问题&#34;实施&#34;向上导航的正确方法是什么?主/详细布局(1活动/ 2片段)? &#34 ;: 典型的方法是在一个FragmentTransaction中添加了2个Fragments,你只需要popBackStack删除它们并返回之前的状态。我认为你通过手动删除FragmentTransaction中的Fragment然后弹出backstack来加倍。试试popBackStack。哦,只是为了确保一致,因为你正在使用ActionBarSherlock和support.v4你使用的是FragmentActivity(而不是Activity)和SherlockFragment吗?

答案 3 :(得分:0)

我认为你应该只在活动中处理Up按钮。 如果您在手机中,则向上按钮将由活动处理,该活动充当该片段的包装,以平板电脑(主/详细模式)表示您不想要它

相关问题