แถบการดำเนินการขึ้นการนำทางด้วยชิ้นส่วน


88

ฉันมีแท็บ Actionbar / viewpager รูปแบบที่มีสามแท็บพูด, BและC ในแท็บCแท็บ (ส่วน) ผมกำลังเพิ่มอีกส่วนพูดส่วนD ด้วย

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

ฉันแก้ไขแถบการดำเนินการในปุ่ม onResume ของ DFragment เพื่อเพิ่ม:

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

ตอนนี้ใน DFragment เมื่อฉันกดปุ่มย้อนกลับของฮาร์ดแวร์ (โทรศัพท์) ฉันจะกลับไปที่เค้าโครงแบบแท็บ (ABC) ดั้งเดิมโดยเลือก CFragment ฉันจะใช้ฟังก์ชันนี้ด้วยปุ่มขึ้นแถบการทำงานได้อย่างไร


คำตอบ:


186

ติดตั้ง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;
}

21
เกี่ยวกับonSupportNavigateUp()"เมธอดไม่ได้ลบล้างเมธอดจากซูเปอร์คลาส"
Fred

10
ถ้าคุณมีอยู่แล้วonOptionsItemSelectedก็ยังสามารถที่จะตรวจสอบ Itemid แทนการเพิ่มandroid.R.id.home onSupportNavigateUp
domsom

1
ถ้าเวอร์ชัน API> = 14 ให้ใช้ onNavigateUp แทน onSupportNavigateUp @Override บูลีนสาธารณะ onNavigateUp () {// วิธีนี้เรียกเมื่อกดปุ่มขึ้น เพียงแค่กองหลังป๊อป getFragmentManager (). popBackStack (); กลับจริง; }
Tejasvi Hegde

1
ควรจะมีเครื่องหมายอัพคาเร็ตที่แสดงถัดจากไอคอนแอพของคุณในActionBar? ฉันไม่เห็นหนึ่งเมื่อฉันใช้โค้ดนี้ ฉันสามารถคลิกที่ไอคอนเท่านั้น แต่มันไม่ได้ทำอะไรเลย Android 4.0 ขึ้นไป
Azurespot

3
หาก onBackStackChanged () ไม่แทนที่ตรวจสอบให้แน่ใจว่ากิจกรรมของคุณใช้อินเทอร์เฟซ FragmentManager OnBackStackChangedListener
CBA110

42

ฉันเข้าใจแล้ว. เพียงแค่แทนที่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
คุณควรใส่รหัสที่อยู่ภายในคำสั่งกับกรณีที่switch android.R.id.home
เฟร็ด

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

1
@ แดเนียลรหัสของคุณถูกต้อง .. มันใช้งานได้ คุณอาจต้องการทำลายมันด้วยตัวเลือกลองจับในกรณี .. คุณรู้เพื่อป้องกันข้อยกเว้นที่คาดไม่ถึงและแอพขัดข้อง
Zuko

1
@NoniA. สิ่งนี้จะย้อนกลับไปยังส่วนก่อนหน้าเท่านั้น (เช่นส่วน B -> ส่วน A) หากคุณกำลังขยาย 1 ส่วนในกิจกรรมใหม่สิ่งนี้จะไม่ย้อนกลับไปที่กิจกรรมก่อนหน้า
Daniel Jonker

11

คุณสามารถย้อนกลับด้วยปุ่มขึ้นเช่นปุ่มย้อนกลับ

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

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

แค่นั้นแหละ.


7

ฉันใช้ส่วนผสมของRoger Garzon Nietoและsohailaziz'sคำตอบกัน แอปของฉันมี MainActivity เพียงรายการเดียวและส่วน A, B, C ที่โหลดลงในแอป ส่วน "บ้าน" ของฉัน (A) ใช้ OnBackStackChangedListener และตรวจสอบขนาดของ backStack หากน้อยกว่าหนึ่งปุ่มจะซ่อนปุ่ม 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

Kotlin:

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

BTW: หากคุณระบุรายการที่ซ้ำกันโปรดตั้งค่าสถานะเป็นเช่นนั้น ขอบคุณ.
bummi

setSelectedFragment ภายใน onStart มีความสำคัญหรือไม่
VLeonovs
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.