动作栏与片段导航

时间:2012-10-26 12:21:00

标签: android android-fragments android-actionbar

我有一个带标签的Actionbar / viewpager布局,其中有三个标签,分别为 A B C 。在标签 C 标签(片段)中,我要添加另一个片段,例如片段 D 。与

 DFragment f= new DFragment();
 ft.add(android.R.id.content, f, "");
 ft.remove(CFragment.this);
 ft.addToBackStack(null);
 ft.commit();

我修改了DFragment的onResume中的操作栏以添加按钮:

ActionBar ab = getActivity().getActionBar();
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
ab.setDisplayHomeAsUpEnabled(true);
ab.setDisplayShowHomeEnabled(true);

现在在DFragment中,当我按下硬件(手机)后退按钮时,我返回到选择了CFragment的原始选项卡(ABC)布局。如何通过操作栏按钮实现此功能?

9 个答案:

答案 0 :(得分:180)

实施OnBackStackChangedListener并将此代码添加到您的片段活动中。

@Override
public void onCreate(Bundle savedInstanceState) {
    //Listen for changes in the back stack
    getSupportFragmentManager().addOnBackStackChangedListener(this);
    //Handle when activity is recreated like on orientation Change
    shouldDisplayHomeUp();
}

@Override
public void onBackStackChanged() {
    shouldDisplayHomeUp();
}

public void shouldDisplayHomeUp(){
   //Enable Up button only  if there are entries in the back stack
   boolean canGoBack = getSupportFragmentManager().getBackStackEntryCount()>0;
   getSupportActionBar().setDisplayHomeAsUpEnabled(canGoBack);
}

@Override
public boolean onSupportNavigateUp() {
    //This method is called when the up button is pressed. Just the pop back stack.
    getSupportFragmentManager().popBackStack();
    return true;
}

答案 1 :(得分:37)

我明白了。只需覆盖托管活动中的 onOptionsItemSelected 并弹出backstack,例如

public boolean onOptionsItemSelected(MenuItem item) {

  switch (item.getItemId()) {
   case android.R.id.home:
     FragmentManager fm = getSupportFragmentManager();
     if (fm.getBackStackEntryCount() > 0) {
          fm.popBackStack();
        }
        return true;
    default:
        return super.onOptionsItemSelected(item);;
    }
}

按照以下答案中的说明,在getActionBar().setDisplayHomeAsUpEnabled(boolean);中致电getActionBar().setHomeButtonEnabled(boolean);onBackStackChanged()

答案 2 :(得分:18)

如果您有一个父活动并希望此向上按钮用作后退按钮,则可以使用此代码:

将此添加到主要活动类

中的onCreate
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            int stackHeight = getSupportFragmentManager().getBackStackEntryCount();
            if (stackHeight > 0) { // if we have something on the stack (doesn't include the current shown fragment)
                getSupportActionBar().setHomeButtonEnabled(true);
                getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            } else {
                getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                getSupportActionBar().setHomeButtonEnabled(false);
            }
        }

    });

然后像这样添加onOptionsItemSelected:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            getSupportFragmentManager().popBackStack();
            return true;
     ....
 }

我通常一直使用这个并且看起来非常合法

答案 3 :(得分:10)

您可以使用向上按钮返回按钮;

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            super.onBackPressed();
            return true;
    }
    return super.onOptionsItemSelected(item);
}

答案 4 :(得分:8)

我知道这个问题很老,但可能有人(像我一样)也需要它。

如果您的活动扩展 AppCompatActivity ,您可以使用更简单的(两步)解决方案:

1 - 每次添加非主页片段时,只需在提交片段事务后立即显示向上按钮。像这样:

    // ... add a fragment
    // Commit the transaction
    transaction.commit();

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

2 - 然后按下UP按钮时,隐藏它。

@Override
public boolean onSupportNavigateUp() {
    getSupportActionBar().setDisplayHomeAsUpEnabled(false);        
    return true;
}

那就是它。

答案 5 :(得分:6)

我使用了Roger Garzon Nieto'ssohailaziz's个答案的组合。我的应用程序只有一个MainActivity,以及加载到其中的片段A,B,C。我的家#34; fragment(A)实现OnBackStackChangedListener,并检查backStack的大小;如果它小于1,则它会隐藏UP按钮。片段B和C总是加载后退按钮(在我的设计中,B从A启动,C从B启动)。 MainActivity本身只是在UP按钮点击时弹出Backstack,并有方法显示/隐藏片段调用的按钮:

<强> MainActivity:

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        // Respond to the action bar's Up/Home button
        case android.R.id.home:
            getSupportFragmentManager().popBackStack();
            return true;
    }
    return super.onOptionsItemSelected(item);
}

public void showUpButton() { getSupportActionBar().setDisplayHomeAsUpEnabled(true); }
public void hideUpButton() { getSupportActionBar().setDisplayHomeAsUpEnabled(false); }

fragmentA(实现FragmentManager.OnBackStackChangedListener):

public void onCreate(Bundle savedinstanceSate) {
    // listen to backstack changes
    getActivity().getSupportFragmentManager().addOnBackStackChangedListener(this);

    // other fragment init stuff
    ...
}

public void onBackStackChanged() {
    // enable Up button only  if there are entries on the backstack
    if(getActivity().getSupportFragmentManager().getBackStackEntryCount() < 1) {
        ((MainActivity)getActivity()).hideUpButton();
    }
}

fragmentB,fragmentC:

public void onCreate(Bundle savedinstanceSate) {
    // show the UP button
    ((MainActivity)getActivity()).showUpButton();

    // other fragment init stuff
    ...
}

答案 6 :(得分:4)

这对我有用。例如,覆盖onSupportNavigateUp和onBackPressed(Kotlin中的代码);

override fun onBackPressed() {
    val count = supportFragmentManager.backStackEntryCount
    if (count == 0) {
        super.onBackPressed()
    } else {
        supportFragmentManager.popBackStack()
    }
}

override fun onSupportNavigateUp(): Boolean {
    super.onSupportNavigateUp()
    onBackPressed()
    return true
}

现在在片段中,如果您显示向上箭头

activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)

点击它会带您回到之前的活动。

答案 7 :(得分:3)

科特林:

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        supportFragmentManager.addOnBackStackChangedListener { setupHomeAsUp() }
        setupHomeAsUp()
    }

    private fun setupHomeAsUp() {
        val shouldShow = 0 < supportFragmentManager.backStackEntryCount
        supportActionBar?.setDisplayHomeAsUpEnabled(shouldShow)
    }

    override fun onSupportNavigateUp(): Boolean = 
        supportFragmentManager.popBackStack().run { true }

    ...
}

答案 8 :(得分:2)

这是一个非常好且可靠的解决方案:http://vinsol.com/blog/2014/10/01/handling-back-button-press-inside-fragments/

这家伙制作了一个抽象片段来处理backPress行为,并使用策略模式在活动片段之间切换。

对于你们中的一些人来说,抽象类可能有一点缺点......

很快,链接的解决方案如下:

// Abstract Fragment handling the back presses

public abstract class BackHandledFragment extends Fragment {
    protected BackHandlerInterface backHandlerInterface;
    public abstract String getTagText();
    public abstract boolean onBackPressed();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(!(getActivity()  instanceof BackHandlerInterface)) {
            throw new ClassCastException("Hosting activity must implement BackHandlerInterface");
        } else {
            backHandlerInterface = (BackHandlerInterface) getActivity();
        }
    }

    @Override
    public void onStart() {
        super.onStart();

        // Mark this fragment as the selected Fragment.
        backHandlerInterface.setSelectedFragment(this);
    }

    public interface BackHandlerInterface {
        public void setSelectedFragment(BackHandledFragment backHandledFragment);
    }
}   

活动中的用法:

// BASIC ACTIVITY CODE THAT LETS ITS FRAGMENT UTILIZE onBackPress EVENTS 
// IN AN ADAPTIVE AND ORGANIZED PATTERN USING BackHandledFragment

public class TheActivity extends FragmentActivity implements BackHandlerInterface {
    private BackHandledFragment selectedFragment;

    @Override
    public void onBackPressed() {
        if(selectedFragment == null || !selectedFragment.onBackPressed()) {
            // Selected fragment did not consume the back press event.
            super.onBackPressed();
        }
    }

    @Override
    public void setSelectedFragment(BackHandledFragment selectedFragment) {
        this.selectedFragment = selectedFragment;
    }
}