带有片段的导航栏


88

我有一个标签式动作条/ viewpager布局三个标签说,和Ç。在标签Ç标签(片段),我加入另一片段发言权片段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中,当我按硬件(电话)“后退”按钮时,我返回到原始的Tabbed(ABC)布局,并选择了CFragment。如何通过操作栏上按钮实现此功能?


Answers:


185

实现OnBackStackChangedListener此代码并将其添加到您的Fragment Activity。

@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;
}

18
关于onSupportNavigateUp(),“方法不会从其超类覆盖方法”。
Fred

9
如果您已经有一个onOptionsItemSelected,也可以检查itemId android.R.id.home而不是添加onSupportNavigateUp
domsom 2014年

1
如果API版本> = 14,则使用onNavigateUp代替onSupportNavigateUp @Override public boolean onNavigateUp(){//按下向上按钮时将调用此方法。只是弹出堆栈。getFragmentManager()。popBackStack(); 返回true;}
Tejasvi Hegde 2014年

1
是否应该在您的应用程序图标旁边显示一个插入符号ActionBar?实现此代码时,我看不到一个。我只能单击该图标,但是它什么也没做。Android 4.0以上版本。
Azurespot 2015年

3
如果没有重写onBackStackChanged(),请确保您的活动实现了FragmentManager.OnBackStackChangedListener接口。
CBA110

40

我知道了。只需在托管活动中覆盖onOptionsItemSelected并弹出后退栈,例如

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

呼叫getActionBar().setDisplayHomeAsUpEnabled(boolean);getActionBar().setHomeButtonEnabled(boolean);onBackStackChanged()如下的答案解释。


3
您还必须调用getActivity()。getActionBar()。setDisplayHomeAsUpEnabled(false); 弹出后堆栈时,要删除向上按钮
JoP 2013年

这不是执行此操作的正确方法。保持启用向上按钮。
Roger Garzon Nieto

1
您应该将该代码放在switchcase语句中android.R.id.home
Fred

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;
     ....
 }

我通常一直都用这个,看起来很合法


1
我试图在我的一个代码中准确地使用此代码,Activity希望它能返回到它最初的片段。当我转到时,后退按钮显示在我的应用程序图标附近Activity,但是我单击该图标,但没有任何反应(应该返回到片段)。知道为什么吗?谢谢。
Azurespot'2

1
@Daniel您的代码合法。您可能只是想用try catch选项来解决这个问题,以防万一..您知道要防止任何无法预料的异常和应用程序崩溃
Olu Smith

1
@NoniA。这只会返回到先前的片段(例如,片段B->片段A),如果您在一个新活动中增加1个片段,则不会返回到先前的活动。
Daniel Jonker

10

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

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

8

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

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

1-每当您添加非本地片段时,只需在提交片段事务之后立即显示向上按钮即可。像这样:

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

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

2-然后按UP按钮,将其隐藏。

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

而已。


7

我结合了Roger Garzon Nietosohailaziz的答案。我的应用程序只有一个MainActivity,并且片段A,B,C已加载到其中。我的“ home”片段(A)实现了OnBackStackChangedListener,并检查backStack的大小;如果小于1,则隐藏UP按钮。片段B和C总是加载后退按钮(在我的设计中,B从A启动,而C从B启动)。MainActivity本身只是在按下UP按钮时弹出后退堆栈,并具有显示/隐藏按钮的方法,这些片段称为:

主要活动:

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();
    }
}

片段B,片段C:

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

    // other fragment init stuff
    ...
}

5

这对我有用。覆盖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)

单击它可以使您返回上一个活动。


5

科特林:

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 }

    ...
}

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;
    }
}

尽管此链接可以回答问题,但最好在此处包括答案的基本部分,并提供链接以供参考。如果链接的页面发生更改,仅链接的答案可能会失效。
bummi 2015年

顺便说一句:如果您发现重复项,请标记为重复项。谢谢。
bummi

在onStart内设置setSelectedFragment是否重要?
VLeonovs
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.