フラグメントによるアクションバーのアップナビゲーション


88

タブ付きのActionbar / viewpagerレイアウトで、ABCの 3つのタブがあります。タブC tab(fragment)で、フラグメント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が選択された元のTabbed(ABC)レイアウトに戻ります。アクションバーのアップボタンでこの機能を実現するにはどうすればよいですか?


回答:


185

OnBackStackChangedListenerこのコードを実装してFragmentアクティビティに追加します。

@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()、「メソッドはスーパークラスのメソッドをオーバーライドしません」。
フレッド

9
既にがある場合は、を追加する代わりにonOptionsItemSelecteditemIdを確認することもできます。android.R.id.homeonSupportNavigateUp
domsom

1
APIバージョン> = 14の場合、onSupportNavigateUpの代わりにonNavigateUpを使用します@Override public boolean onNavigateUp(){//このメソッドは、上ボタンが押されたときに呼び出されます。ちょうどポップバックスタック。getFragmentManager()。popBackStack(); trueを返します。}
Tejasvi Hegde 2014

1
のアプリアイコンの横に表示されるアップキャレットがあるはずActionBarですか?このコードを実装しても、表示されません。アイコンをクリックするだけですが、何も実行されません。Android 4.0以降。
Azurespot 2015

3
onBackStackChanged()がオーバーライドしない場合は、アクティビティがFragmentManager.OnBackStackChangedListenerインターフェースを実装していることを確認してください。
CBA110 2016年

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

これはこれを行う正しい方法ではありません。上ボタンを有効にしたままにします。
Roger Garzon Nieto

1
そのコードをswitchcase付きのステートメント内に配置する必要がありますandroid.R.id.home
フレッド

18

親アクティビティが1つあり、この上ボタンを戻るボタンとして機能させたい場合は、次のコードを使用できます。

これをメインアクティビティクラスの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 2015

1
@ダニエルあなたのコードは合法です..それは動作します。場合によっては、try catchオプションを使用して問題を回避することもできます。予期しない例外やアプリのクラッシュを防ぐことがわかっています
Olu Smith

1
@NoniA。これは前のフラグメント(たとえば、フラグメントB->フラグメントA)に戻るだけです。新しいアクティビティで1つのフラグメントを膨らませている場合、これは前のアクティビティに戻りません。
Daniel Jonker、2015

10

戻るボタンのような上ボタンで戻ることができます。

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

8

私はこの質問が古いことを知っていますが、(私のような)誰かがそれを必要としているのかもしれません。

アクティビティがAppCompatActivityを拡張する場合、より簡単な(2ステップの)ソリューションを使用できます。

1-非ホームフラグメントを追加するときはいつでも、フラグメントトランザクションをコミットした直後に、[上へ]ボタンを表示するだけです。このような:

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

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

2-次にUPボタンを押すと、非表示になります。

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

それでおしまい。


7

私はロジャーガルソンニエト回答とソハイラジズの回答を組み合わせて使用​​しました。私のアプリには、MainActivityが1つあり、それに読み込まれるフラグメントA、B、Cがあります。私の「ホーム」フラグメント(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();
    }
}

fragmentB、fragmentC:

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 2015年

onStart内でsetSelectedFragmentを設定することは重要ですか?
VLeonovs 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.