【问题标题】:Replace Fragment with another on back button用另一个后退按钮替换 Fragment
【发布时间】:2015-07-23 14:51:39
【问题描述】:

我正在尝试覆盖后退按钮,因为当我按下时它正在关闭我的应用程序,我有不同的片段:

  • 片段 A:索引(当我按下返回按钮时,它将关闭应用程序)
  • 片段 B(当我按下返回按钮时,它将返回片段 A)
  • 片段 C(当我按下返回按钮时,它将返回片段 A)

我有我的主要活动:它管理我的片段(因为有一个导航抽屉)。

我发现了很多关于此的帖子,但我无法实现它们:

以片段 B 为例:

@Override
public void onBackPressed(){
    FragmentManager fm = getSupportFragmentManager();
    Fragment f = fm.findFragmentById(R.id.fragmentb); // get the fragment that is currently loaded in placeholder
    Object tag = f.getTag();
    // do handling with help of tag here
    // call super method
    super.onBackPressed();
}

上面说onBackPressed() 和getSupportFragmentManager() 无法解析,我想我没有正确使用方法,怎么办?

活动:

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Typeface;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements FragmentDrawer.FragmentDrawerListener {

    private static String TAG = MainActivity.class.getSimpleName();
    private Toolbar mToolbar;
    private FragmentDrawer drawerFragment;

    //Initialisation de l activite avec les donnees necessaires
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        drawerFragment = (FragmentDrawer)getSupportFragmentManager().findFragmentById(R.id.fragment_navigation_drawer);
        drawerFragment.setUp(R.id.fragment_navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), mToolbar);
        drawerFragment.setDrawerListener(this);
        // Affichage de la navigation
        displayView(0);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //Ajout des items
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onDrawerItemSelected(View view, int position) {
        displayView(position);
    }

    private void displayView(int position) {
        Fragment fragment = null;
        String title = getString(R.string.app_name);
        switch (position) {
            case 0:
                fragment = new Accueil();
                title = getString(R.string.title_accueil);
                break;
            case 1:
                fragment = new NosOffres();
                title = getString(R.string.title_nosoffres);
                break;
            case 2:
                fragment = new DemandeGratuite();
                title = getString(R.string.title_demandegratuite);
                break;
            case 3:
                fragment = new ContactezNous();
                title = getString(R.string.title_contact);
                break;
            case 4:
                fragment = new Actualites();
                title = getString(R.string.title_actu);
                break;
            case 5:
                fragment = new MentionsLegales();
                title = getString(R.string.title_mentions);
                break;
            default:
                break;
        }

        if (fragment != null) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.replace(R.id.container_body, fragment);
            fragmentTransaction.commit();
            // libelle du toolbar
            TextView titlet;
            titlet = (TextView) findViewById(R.id.main_toolbar_title);
            titlet.setText(title);
            titlet.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/GothamBook.ttf"));
        }
    }
}

@jujyfruits

我试过了,还是不行:

    @Override
    public void onBackPressed(){
        Fragment myFragment = getSupportFragmentManager().findFragmentById(R.id.demande_gratuite);
        if (myFragment != null && myFragment.isVisible()) {
            AlertDialog alertDialog = new AlertDialog.Builder(this).create();
            alertDialog.setTitle("Reset...");
            alertDialog.setMessage("test");
            alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                }
            });
            alertDialog.show();
        }
        super.onBackPressed();
    }
}

@AutonomousApps

public class MainActivity extends AppCompatActivity implements FragmentDrawer.FragmentDrawerListener {

    private static String TAG = MainActivity.class.getSimpleName();
    private Toolbar mToolbar;
    private FragmentDrawer drawerFragment;

    //Initialisation de l activite avec les donnees necessaires
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        drawerFragment = (FragmentDrawer)getSupportFragmentManager().findFragmentById(R.id.fragment_navigation_drawer);
        drawerFragment.setUp(R.id.fragment_navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), mToolbar);
        drawerFragment.setDrawerListener(this);
        // Affichage de la navigation
        displayView(0);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //Ajout des items
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onDrawerItemSelected(View view, int position) {
        displayView(position);
    }

    private void displayView(int position) {
        Fragment fragment = null;
        String title = getString(R.string.app_name);
        switch (position) {
            case 0:
                fragment = new Accueil();
                title = getString(R.string.title_accueil);
                break;
            case 1:
                fragment = new NosOffres();
                title = getString(R.string.title_nosoffres);
                break;
            case 2:
                fragment = new DemandeGratuite();
                title = getString(R.string.title_demandegratuite);
                break;
            case 3:
                fragment = new ContactezNous();
                title = getString(R.string.title_contact);
                break;
            case 4:
                fragment = new Actualites();
                title = getString(R.string.title_actu);
                break;
            case 5:
                fragment = new MentionsLegales();
                title = getString(R.string.title_mentions);
                break;
            default:
                break;
        }

        if (fragment != null) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.replace(R.id.container_body, fragment);
            fragmentTransaction.addToBackStack("name");
            fragmentTransaction.commit();
            // libelle du toolbar
            TextView titlet;
            titlet = (TextView) findViewById(R.id.main_toolbar_title);
            titlet.setText(title);
            titlet.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/GothamBook.ttf"));
        }
    }

    @Override
    public void onBackPressed(){
        FragmentManager mgr = getSupportFragmentManager();
        if (mgr.getBackStackEntryCount() == 0) {
            super.onBackPressed();
        }else{
             mgr.popBackStack();
        }
    }

【问题讨论】:

  • 你的 activity 有片段管理器(我认为还有 onBackPressed() 调用),而不是片段。
  • @EpicPandaForce 但是如果我把 Override public void onBackPressed() { super.onBackPressed();在 MainActivity 我将如何为不同的片段配置后退按钮?
  • @benjy 是否愿意发布活动代码?
  • @benjy 正如两个答案所说,您没有在活动中覆盖 onBackPressed。
  • @milez 我在这里做了:覆盖 public void onBackPressed(){ }

标签: android fragment back-button


【解决方案1】:

这是我在片段之间导航时使用的:

MainActivity.java:

@Override
public void onBackPressed() {
    // note: you can also use 'getSupportFragmentManager()'
    FragmentManager mgr = getFragmentManager();
    if (mgr.getBackStackEntryCount() == 0) {
        // No backstack to pop, so calling super
        super.onBackPressed();
    } else {
        mgr.popBackStack();
    }
}

编辑第二个:请注意,如果您还没有处理过super.onBackPressed(),您只需要调用它(例如,通过弹出片段管理器的后台堆栈)。

为此,您必须将新片段添加到您的 FragmentManager 的后台堆栈 (addToBackStack())。例如(也在 MainActivity.java 中):

private void displayView(int position) {
    Fragment fragment = ...; // YOUR CODE HERE
    if (fragment != null) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.container_body, fragment);

        // ADD THIS LINE
        fragmentTransaction.addToBackStack("name"); // name can be null

        fragmentTransaction.commit();
        // libelle du toolbar
        TextView titlet;
        titlet = (TextView) findViewById(R.id.main_toolbar_title);
        titlet.setText(title);
        titlet.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/GothamBook.ttf"));
    }
}

编辑第三个 (7/28): 在您的 onCreate(Bundle) 方法中,您通过调用您的 displayView(int) 方法来执行您的第一个片段事务。 displayView(int) 总是 将其片段事务添加到后台堆栈。这不是你想要的。非常第一个片段事务应该使用fragmentTransaction.**add**(int, Fragment)并且应该调用addToBackStack(String)。每笔交易之后第一个应该调用fragmentTransaction.**replace**(int, Fragment)并且应该调用addToBackStack(String)。这样做的原因是您第一个 事务基本上是将片段(您的 UI)“添加”到空容器(它不是“替换”另一个片段)。当这个事务在 backstack 上时,这意味着空容器状态是 also 在 backstack 上。因此,当您弹出最后一笔交易时,它会显示一个空白 UI。

编辑第一个:当您在 FragmentTransaction 对象上调用 addToBackStack(String name)(通过调用 getFragmentManager().beginTransaction() 获得)时,您将在 FragmentTransaction 添加 FragmentTransaction s 'backstack'。我的代码所做的是通过调用getFragmentManager.getBackStackEntryCount() 检查后台堆栈的size。如果该数字大于零,那么我们知道我们在后台堆栈中有FragmentTransactions。在这种情况下,您可以调用 getFragmentManager.popBackStack(),这会将最后一个事务从后台堆栈中弹出——换句话说,将您的应用程序返回到显示的最后一个 Fragment。

如果 backstack entry 县等于 0,那么这意味着你在 Fragment A,你应该调用super.onBackPressed(),这将导致应用退出。

【讨论】:

  • 我不明白第二个代码我必须做什么......以及FragmentManager的backstack是什么
  • 见我的补充说明。如果您需要更多信息,请与我们联系。您绝对应该阅读文档和 Google 开发者指南以获取片段。
  • 我更改了示例以反映您用于片段事务的代码。
  • 在您的自定义 onBackPressed() 方法中不要调用 super.onBackPressed() 非常重要,除非您在 Fragment A 并想返回主屏幕。这就是为什么我将我的超级调用包含在 else 声明中。
  • 完美的解释!它看起来工作正常,但我有另一个问题,我可以从 Accueil Fragment 访问另一个片段,你知道如何做 Navigation 之类的链接吗?请看这里:stackoverflow.com/questions/31674571/… 但是感谢您的宝贵时间! :)
【解决方案2】:

onBackPressed()getSupportFragmentManager() 是来自 Activity 类的方法,而不是 Fragment,因此您必须在 Activity 而不是 Fragment 上实现它。 如果您只想为一个片段实现特定行为,您可以检查当前可见片段是什么,然后实现您的行为。像这样:

@Override
public void onBackPressed(){
    MyFragment myFragment =   (MyFragment)getFragmentManager().findFragmentByTag("YOUR_FRAGMENT");
    if (myFragment != null && myFragment.isVisible()) {
       // the code for whatever behaviour you want goes here
    }
    else
       super.onBackPressed();
}

另一种可能的、可能更简单的方法是在添加片段时激活的 Activity 中使用一些标志,然后从 onBackPressed() 中读取。

针对 BENJY 的编辑进行编辑

请注意,您并没有完全使用我发布的代码。您正在使用findFragmentById(),它并不适用于所有情况,我无法判断它是否适合您的代码。 您应该使用适用于任何类型的片段事务的findFragmentByTag。 只需在进行交易时为您的片段添加一个标签,如下所示:

 getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, new PlaceholderFragment(), "FRAGMENT_TAG")
                    .commit();

然后,当您尝试取回 onBackPressed() 中的 Fragment 时,它会寻找该标签:

PlaceholderFragment myFragment = (PlaceholderFragment) getSupportFragmentManager()
   .findFragmentByTag("FRAGMENT_TAG");

进行此更改,它必须起作用。

【讨论】:

  • @benjy 代码已添加到您的活动类中,对吧?
  • 是的,查一下我做了你的代码并添加一条消息,看看它是否有效,但没办法:)
  • @benjy 看看我的编辑。如果您更改我提到的内容,它必须起作用。我在发布之前尝试确保它对我有用。
  • 我同意 jujyfruits 的观点,你最好使用findFragmentByTag()
  • 我已经替换,你使用 add:getSupportFragmentManager().beginTransaction().add(R.id.container, fragment, "FRAGMENT_TAG")commit();getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "FRAGMENT_TAG")commit 是一样的吗?
【解决方案3】:

我知道这为时已晚,但无论谁访问这里,可能会得到帮助,我通过下面实现了这一点。

如果您想更改在单击设备后退按钮时保持活动的片段,上述所有代码都可以删除以下行。

super.onBackPressed()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 2013-09-06
    • 1970-01-01
    • 1970-01-01
    • 2017-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多