Làm thế nào để tôi có được đoạn hiện đang hiển thị?


444

Tôi đang chơi với các mảnh vỡ trong Android.

Tôi biết tôi có thể thay đổi một đoạn bằng cách sử dụng đoạn mã sau:

FragmentManager fragMgr = getSupportFragmentManager();
FragmentTransaction fragTrans = fragMgr.beginTransaction();

MyFragment myFragment = new MyFragment(); //my custom fragment

fragTrans.replace(android.R.id.content, myFragment);
fragTrans.addToBackStack(null);
fragTrans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fragTrans.commit();

Câu hỏi của tôi là, trong một tệp Java, làm cách nào tôi có thể lấy cá thể Fragment hiện đang hiển thị?



1
Bản sao có thể có của Lấy đối tượng mảnh hiện tại
Snut A.Suk

Câu trả lời:


453

Khi bạn thêm đoạn trong giao dịch của mình, bạn nên sử dụng thẻ.

fragTrans.replace(android.R.id.content, myFragment, "MY_FRAGMENT");

... Và sau này nếu bạn muốn kiểm tra xem đoạn này có hiển thị không:

MyFragment myFragment = (MyFragment)getFragmentManager().findFragmentByTag("MY_FRAGMENT");
if (myFragment != null && myFragment.isVisible()) {
   // add your code here
}

Xem thêm http://developer.android.com/reference/android/app/Fragment.html


74
Ok, nhưng tôi cần một cách để lấy ngay đối tượng Fragment hiện đang hiển thị, không kiểm tra lặp lại tất cả các đoạn và sau đó quyết định đoạn nào hiện được hiển thị trên màn hình. Tôi nghĩ rằng câu trả lời của bạn cần mã của tôi để kiểm tra lặp lại từng phân đoạn của tôi và tìm ra cái có thể nhìn thấy ...
Leem.fin

33
Có, nhưng có thể có nhiều hơn một mảnh có thể nhìn thấy cùng một lúc. Vì vậy, không có gì giống như "đoạn hoạt động duy nhất" ....
ramdroid

6
Ok, thậm chí có một vài mảnh được hiển thị, tôi vẫn cần một cách để có được chúng ... và một cách tốt hơn là kiểm tra lặp lại từng mảnh của tôi. Tôi lo ngại về việc "lấy chúng" một phương thức như getDisplayedFragment (), nhưng không chắc có phương thức như vậy trong Android
Leem.fin

2
Tôi không biết tại sao đây lại là vấn đề với bạn ... Bạn thường chỉ có một vài mảnh vỡ trong một hoạt động và nó thực sự không phải là vấn đề để kiểm tra xem chúng có nhìn thấy được hay không.
ramdroid

12
Tại sao tất cả mọi người nâng cao câu trả lời này? Chắc chắn, đó là một đoạn mã đẹp nhưng không trả lời câu hỏi để có được một đoạn cụ thể bằng thẻ .. NHƯNG Asker muốn đoạn được hiển thị hiện tại, có nghĩa là anh ta không biết đoạn nào được hiển thị. Có, có thể có nhiều đoạn, nhưng đọc câu hỏi chỉ có 1 đoạn được hiển thị trên giao diện người dùng .... Xin lỗi đã phải tải xuống vì nó không trả lời bối cảnh câu hỏi.
tức giận

410

Tôi biết đó là một bài viết cũ, nhưng trước đây cũng gặp rắc rối với nó. Tìm thấy một giải pháp để làm điều này trong onBackStackChanged()chức năng nghe

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

         Fragment f = getActivity().getFragmentManager().findFragmentById(R.id.fragment_container);
      if(f instanceof CustomFragmentClass) 
        // do something with f
        ((CustomFragmentClass) f).doSomething();

    }

Điều này làm việc cho tôi vì tôi không muốn lặp đi lặp lại qua từng mảnh mà tôi phải tìm một thứ có thể nhìn thấy. Hy vọng nó sẽ giúp người khác quá.


13
Chính xác những gì tôi đang tìm kiếm khi xử lý onBackPression () sau khi xoay màn hình với Ngăn kéo Điều hướng. Cảm ơn đã trở lại để chia sẻ điều này.
ShortFuse

1
Không tìm thấyFragmentById lặp đi lặp lại qua tất cả các mảnh bên trong? :)
Andrew Senner

46
trong trường hợp .getFragmentManagerbáo cáo loại không tương thích, như trong trường hợp của tôi, đó là do tôi đang sử dụng android.support.app.v4.Fragment, trong trường hợp đó phương pháp đúng để sử dụng làgetSupportFragmentManager
Răzvan Barbu

3
hoặc bạn có thể sử dụng findFragmentByTag()thay thế findFragmentById, nếu bạn đã cung cấp thẻ cho đoạn khi thêm nó vàofragmentManager.beginTransaction() .add(containerID, frag, fragmentTag) .addToBackStack(fragmentTag) .commit();
DeltaCap019

@AndrewSenner, anh ta có nghĩa là anh ta không muốn làm điều đó một cách rõ ràng :)
Farid

161

Đây là giải pháp của tôi mà tôi thấy hữu ích cho các tình huống phân đoạn thấp

public Fragment getVisibleFragment(){
    FragmentManager fragmentManager = MainActivity.this.getSupportFragmentManager();
    List<Fragment> fragments = fragmentManager.getFragments();
    if(fragments != null){
        for(Fragment fragment : fragments){
            if(fragment != null && fragment.isVisible())
                return fragment;
        }
    }
    return null;
}

13
fragmentcó thể là null trong các trường hợp nhất định, chẳng hạn như khi bạn bật ngăn xếp trở lại. Vì vậy, sử dụng tốt hơn if (fragment != null && fragment.isVisible()).
cprcrack

8
phương pháp không đầy đủ vì có thể không chỉ có một đoạn có thể nhìn thấy
hãy đăng ký

Nếu không có đoạn nào hiển thị, thì FragmentManager.getFragments () sẽ trả về NULL, điều này sẽ dẫn đến NPE nói "Cố gắng gọi phương thức giao diện 'java.util.Iterator java.util.List.iterator ()' trên tham chiếu đối tượng NULL". Do đó, vòng lặp for nên được bao quanh bởi một kiểm tra đơn giản: if (Fragment! = Null)
Pranav Mahajan

Điều gì nếu nhiều hơn một mảnh được nhìn thấy?
Shivaraj Patil

5
Về mặt kỹ thuật, điều này nên được đánh dấu là câu trả lời dựa trên câu hỏi. Asker muốn hiện đang hiển thị đoạn, không biết đó là đoạn nào. Các câu trả lời khác tiếp tục nhận được các đoạn bằng thẻ
AngryITguy

76

Mỗi khi bạn hiển thị đoạn, bạn phải đặt thẻ vào backstack:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_ENTER_MASK);       
ft.add(R.id.primaryLayout, fragment, tag);
ft.addToBackStack(tag);
ft.commit();        

Và sau đó khi bạn cần lấy đoạn hiện tại, bạn có thể sử dụng phương pháp này:

public BaseFragment getActiveFragment() {
    if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
        return null;
    }
    String tag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
    return (BaseFragment) getSupportFragmentManager().findFragmentByTag(tag);
}

4
Tôi khá chắc chắn rằng kỹ thuật này sẽ không hoạt động đối với các Mảnh được sử dụng với ViewPager, vì chúng không được thêm bởi thẻ. Chỉ cần ném nó ra khỏi đó.
loeschg

3
Điều này dường như chỉ hoạt động khi bạn gọi addToBackStack(tag), nhưng nếu bạn không thêm mảnh vào ngăn xếp phía sau thì sao?
cprcrack

1
Điều này chỉ hoạt động nếu thẻ của bạn giống với tên ngăn xếp phía sau, có vẻ như nó không bình thường.

Điều gì xảy ra nếu bạn thêm 5 mảnh trong cùng một giao dịch?
Kevin Lam

Có thể rất hay khi nói rằng nếu bạn gọi addToBackStack (null) cho một số Fragment mà bạn không cần tên, phương thức getName () có thể trả về null và bạn nhận được NPE. @ dpk, docu nói: Lấy tên được cung cấp cho FragmentTransaction.addToBackStack (Chuỗi) khi tạo mục nhập này. Ngoài ra, thêm kiểm tra null nếu EntryCount bằng 0 và bạn cố gắng nhận mục nhập hàng đầu.
JacksOnF1re

23

Những gì tôi đang sử dụng để tìm đoạn hiển thị hiện tại nằm trong đoạn mã dưới đây. Nó là đơn giản và nó làm việc cho tôi bây giờ. Nó chạy trong hoạt động chứa các mảnh

    FragmentManager fragManager = this.getSupportFragmentManager();
    int count = this.getSupportFragmentManager().getBackStackEntryCount();
    Fragment frag = fragManager.getFragments().get(count>0?count-1:count);

3
Bạn nên kiểm tra để chắc chắn đếm> 0 để get (đếm-1) không ném IndexOutofBoundException
kehers

@tainy điều này sẽ không cung cấp cho các mảnh đã được thay thế nhưng không được thêm vào backstack .Right? Nếu có, sau đó tôi có thể lấy nó bằng cách sử dụng đối số thẻ không?
cafebabe1991

Cuộc gọi getFragments sẽ không cung cấp cho bạn các đoạn mà chúng được thêm sau khi bạn gọi popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE) trên đó và thêm các đoạn khác.
LEHO

nếu hoạt động có nhiều hơn một mảnh hiển thị, cách của bạn là sai. Ví dụ: ViewPager với Fragment. như tôi đã biết getBackStackEntryCount () số lần trả lại của Giao dịch, không phải số phân đoạn
HungNM2

Bạn nên kiểm tra fragManager.getFragments().size()thay vì getBackStackEntryCount()chúng không nhất thiết phải bằng nhau (đó là trường hợp của tôi). Nếu không, bạn có thể gặp sự cố với IndexOutOfBoundException
RustamG

19

Cách Kotlin;

val currentFragment = supportFragmentManager.fragments.last()

Chỉ hoạt động trên API 26 trở lên
ibit 24/03/19

1
@ibit Ý bạn là gì khi chỉ hoạt động trên API 26 trở lên? Tôi đã thử trên trình giả lập API 19 hoạt động tốt.
HendraWD

@HendraWD bạn đúng rồi! Tôi đã đề cập đến chức năng trong getFragments()chức năng khung , đó là API 26 trở lên.
ibit

2
bảo trọng. Nếu trước khi bạn không có bất kỳ ngăn xếp mảnh, nó có thể gây ra ngoại lệ trống!
Jetwiz

Điều này không hiệu quả? java.lang.ClassCastException: androidx.navlation.fragment.NavhostFragment không thể được chuyển thành Fragment
coolcool1994

13

Cách phản ứng :

Observable.from(getSupportFragmentManager().getFragments())
    .filter(fragment -> fragment.isVisible())
    .subscribe(fragment1 -> {
        // Do something with it
    }, throwable1 -> {
        // 
    });

7
Làm thế nào là phản ứng? Bạn sử dụng một thiết bị quan sát được nhưng nó sẽ chỉ phát ra một lần
Tim

6
Và nó chỉ là một quá mức cần thiết. Một forloop nâng cao đơn giản sẽ làm tương tự, thậm chí có thể nhanh hơn.
Peterstev Uremgba

sử dụng luồng phản ứng cho luồng api không thông minh, thực tế như họ nói rằng đó là việc sử dụng api Java8 hơi quá mức nếu bạn muốn coi danh sách là luồng và áp dụng bộ lọc api
AndroidLover 24/07/18

13

Phương pháp của tôi dựa trên thử / bắt như thế này:

MyFragment viewer = null;
    if(getFragmentManager().findFragmentByTag(MY_TAG_FRAGMENT) instanceOf MyFragment){
    viewer = (MyFragment) getFragmentManager().findFragmentByTag(MY_TAG_FRAGMENT);
}

Nhưng có thể có một cách tốt hơn ...


1
Câu hỏi của tôi là làm thế nào để có được đoạn hiện đang hiển thị, điều đó có nghĩa là có thể có rất nhiều đoạn, tôi chỉ muốn lấy ví dụ của đoạn hiện đang hiển thị, tại sao lại sử dụng (MyFragment) ?? Ý tôi là nó có thể là bất kỳ màn hình Fragment nào trên màn hình ... và tôi muốn lấy cái đang hiển thị.
Leem.fin

MYiah_FRAGMENT là thẻ của đoạn tôi đã tạo trước khi sử dụng thay thế, như thế này: FragmentTransaction.replace (R.id.FL_MyFragment, MyFragment, MYiah_FRAGMENT);
Thordax

Nếu tôi có nhiều phân đoạn, tôi có thể sử dụng một thẻ cho tất cả các phân đoạn khi gọi .replace (...) không?
Leem.fin

Có, không có vấn đề gì, hãy sử dụng mã này: FragmentTransaction.replace (R.id.FL_MyFragment, MyFragment, MYiah_FRAGMENT); và nó có thể đi tốt
Thordax

1
Chà, tôi thực sự không hiểu ý của bạn, ý tôi là tôi cần một cách để lấy ngay ví dụ Fragment hiện đang hiển thị, không kiểm tra lặp lại tất cả các đoạn và sau đó quyết định đoạn nào hiện được hiển thị trên màn hình.
Leem.fin

11

Chà, câu hỏi này nhận được rất nhiều lượt xem và sự chú ý nhưng vẫn không chứa giải pháp đơn giản nhất từ ​​cuối của tôi - sử dụng getFragments ().

            List fragments = getSupportFragmentManager().getFragments();
            mCurrentFragment = fragments.get(fragments.size() - 1);

1
Thật không may, điều này không phải lúc nào cũng đúng, nó getSupportFragmentManager().getFragments() cung cấp cho bạn một danh sách nhưng có thể chứa các giá trị null, nếu đoạn mới nhất vừa được bật ra từ backstack. Phương trình: Nếu bạn kiểm tra theo cách của bạn bên trong onBackStackChanged()phương thức và bạn gọi đến popBackStack()một nơi nào đó, thì mCurrentFragmentsẽ là như vậy null.
Stumi

@Stumi Cảm ơn thông tin này. Đúng, nghe có vẻ như một trong nhiều vấn đề vòng đời kỳ lạ trong Android.
Nativ

9

Bạn có thể truy vấn đoạn nào được tải vào khung nội dung Hoạt động của bạn và truy xuất lớp phân đoạn hoặc đoạn 'tên đơn giản' (dưới dạng chuỗi).

public String getCurrentFragment(){
     return activity.getSupportFragmentManager().findFragmentById(R.id.content_frame).getClass().getSimpleName();
}

Sử dụng:

Log.d(TAG, getCurrentFragment());

Đầu ra:

D/MainActivity: FragOne

8

Hơi muộn một chút, nhưng với bất kỳ ai quan tâm: Nếu bạn biết chỉ số của đoạn mong muốn của mình trong FragmentManager, hãy lấy tham chiếu đến nó và kiểm tra hàm isMothyVisible ()! đây :

getSupportFragmentManager().getFragments().get(0).isMenuVisible()

Nếu truenó hiển thị cho người dùng và như vậy!


1
Thật kỳ lạ, đây là giải pháp duy nhất được liệt kê ở đây làm việc cho tôi. Đồng thời, nhiều mảnh vỡ có thể có isVisible() == true, getView() != null. Thêm vào đó, trong mã của tôi getBackStackEntryCountluôn luôn bằng không. Mặc dù tôi không sử dụng thực đơn, isMenuVisible()cho đến nay là người phân biệt đối xử duy nhất dường như chỉ ra một cách đáng tin cậy cho đoạn hiện đang 'hoạt động'. ty
parvus

7

1)

ft.replace(R.id.content_frame, fragment, **tag**).commit();

2)

FragmentManager fragmentManager = getSupportFragmentManager();
Fragment currentFragment = fragmentManager.findFragmentById(R.id.content_frame);

3)

if (currentFragment.getTag().equals(**"Fragment_Main"**))
{
 //Do something
}
else
if (currentFragment.getTag().equals(**"Fragment_DM"**))
{
//Do something
}

6

Nếu đến đây và bạn đang sử dụng Kotlin:

var fragment = supportFragmentManager.findFragmentById(R.id.fragment_container)

R.id.fragment_containeridnơifragment trình bày về họactivity

Hoặc nếu bạn muốn một giải pháp đẹp hơn:

supportFragmentManager.findFragmentById(R.id.content_main)?.let {
    // the fragment exists

    if (it is FooFragment) {
        // The presented fragment is FooFragment type
    }
}

5

Lấy cảm hứng từ câu trả lời của Tainy , đây là hai xu của tôi. Ít sửa đổi từ hầu hết các thực hiện khác.

private Fragment getCurrentFragment() {
    FragmentManager fragmentManager = myActivity.getSupportFragmentManager();
    int stackCount = fragmentManager.getBackStackEntryCount();
    if( fragmentManager.getFragments() != null ) return fragmentManager.getFragments().get( stackCount > 0 ? stackCount-1 : stackCount );
    else return null;
}

Thay thế "myActivity"bằng "cái này" nếu đó là hoạt động hiện tại của bạn hoặc sử dụng tham chiếu đến hoạt động của bạn.


5

Có một phương pháp gọi findFragmentById()trong SupportFragmentManager. Tôi sử dụng nó trong thùng chứa hoạt động như:

public Fragment currentFragment(){
    return getSupportFragmentManager().findFragmentById(R.id.activity_newsfeed_frame);
}

Đó là cách để có được hiện tại của bạn Fragment. Nếu bạn có tùy chỉnh Fragmentvà cần kiểm tra xem Fragmentđó là gì , tôi thường sử dụng instanceof:

if (currentFragment() instanceof MyFrag){
    // Do something here
}

5

Nếu bạn đang sử dụng AndroidX Navigation:

val currentFragment = findNavController(R.id.your_navhost).?currentDestination

Để biết thêm thông tin về thành phần điều hướng này: https://developer.android.com/guide/navlation/navlation-getting-started


Điều này không được biên dịch
IgorGanapolsky

1
Nó sẽ chỉ biên dịch nếu bạn đã thiết lập điều hướng AndroidX đúng cách và bằng cách nào đó được gọi là navhost của bạn your_navhost.
Cory Roy

4

Đây là cách đơn giản để có được đoạn hiện tại ..

getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
  @Override public void onBackStackChanged() {
    currentFragment = fragmentManager.findFragmentById(R.id.content);
    if (currentFragment !=  null && (currentFragment instanceof LoginScreenFragment)) {
      logout.setVisibility(View.GONE);
    } else {
      logout.setVisibility(View.VISIBLE);
    }
  }
});

4

Câu trả lời của Sev hoạt động khi bạn nhấn nút quay lại hoặc thay đổi backstack.

Tôi đã làm một cái gì đó hơi khác nhau, mặc dù. Tôi có một thiết lập trình nghe thay đổi backstack trên một Fragment cơ sở và các đoạn có nguồn gốc của nó và mã này nằm trong trình nghe:

Fragment f = getActivity().getSupportFragmentManager().findFragmentById(R.id.container);

if (f.getClass().equals(getClass())) {
    // On back button, or popBackStack(),
    // the fragment that's becoming visible executes here,
    // but not the one being popped, or others on the back stack

    // So, for my case, I can change action bar bg color per fragment
}

3

Đây là công việc cho tôi. Tôi hy vọng điều này sẽ làm phiền ai đó.

FragmentManager fragmentManager = this.getSupportFragmentManager();  
        String tag = fragmentManager
                    .getBackStackEntryAt(
                    fragmentManager
                    .getBackStackEntryCount() - 1)
                    .getName();
              Log.d("This is your Top Fragment name: ", ""+tag);

3

Nếu bạn nhận được phiên bản hiện tại của Fragment từ hoạt động chính, bạn có thể chỉ cần

findFragmentByID(R.id.container);

Điều này thực sự có được ví dụ hiện tại của mảnh vỡ được đưa vào chế độ xem. Tôi gặp vấn đề tương tự. Tôi đã phải tải cùng một đoạn hai lần giữ một cái ở phía sau.

Phương pháp sau không hoạt động. Nó chỉ nhận được một mảnh có thẻ. Đừng lãng phí thời gian của bạn vào phương pháp này. Tôi chắc chắn rằng nó có sử dụng nhưng để có được phiên bản mới nhất của cùng một mảnh vỡ thì không phải là một trong số chúng.

findFragmentByTag()

3

Kiểm tra giải pháp này. Nó làm việc cho tôi để có được mảnh vỡ hiện tại.

if(getSupportFragmentManager().getBackStackEntryCount() > 0){
        android.support.v4.app.Fragment f = 
         getSupportFragmentManager().findFragmentById(R.id.fragment_container);
        if(f instanceof ProfileFragment){
            Log.d(TAG, "Profile Fragment");
        }else if(f instanceof SavedLocationsFragment){
            Log.d(TAG, "SavedLocations Fragment");
        }else if(f instanceof AddLocationFragment){
            Log.d(TAG, "Add Locations Fragment");
        }

2
final FragmentManager fm=this.getSupportFragmentManager();
final Fragment fragment=fm.findFragmentByTag("MY_FRAGMENT");

if(fragment != null && fragment.isVisible()){
      Log.i("TAG","my fragment is visible");
}
else{
      Log.i("TAG","my fragment is not visible");
}

Điều này hoạt động với Jetpack?
IgorGanapolsky

2
getSupportFragmentManager().findFragmentById(R.id.content_frame).getClass().getSimpleName();

Chà, tôi đoán đây là câu trả lời thẳng thắn nhất cho câu hỏi này. Tôi hi vọng cái này giúp được.


2

Đây là một giải pháp của Kotlin:

if ( this.getSupportFragmentManager().getBackStackEntryCount()>0 ) {
    var fgmt = this.getSupportFragmentManager().fragments[this.getSupportFragmentManager().getBackStackEntryCount()-1]
    if( fgmt is FgmtClassName ) {
        (fgmt as FgmtClassName).doSth()
    }
}

Cách đơn giản hóa:

with ( this.getSupportFragmentManager() ) {
    if ( getBackStackEntryCount()>0 ) {
        var fgmt = fragments[getBackStackEntryCount()-1]
        if ( fgmt is FgmtClassName ) {
            (fgmt as FgmtClassName).doSth()
        }
    }
}

2

Cách dễ dàng để làm điều đó:

Fragment fr=getSupportFragmentManager().findFragmentById(R.id.fragment_container);
String fragmentName = fr.getClass().getSimpleName();

1

Trong hoạt động chính, phương thức onAttachFragment (Fragment Fragment) được gọi khi một đoạn mới được gắn vào hoạt động. Trong phương thức này, bạn có thể lấy ví dụ của đoạn hiện tại. Tuy nhiên, phương thức onAttachFragment không được gọi khi một đoạn được bật ra khỏi backstack, tức là khi nhấn nút quay lại để lấy đoạn trên cùng của ngăn xếp. Tôi vẫn đang tìm kiếm một phương thức gọi lại được kích hoạt trong hoạt động chính khi một đoạn được hiển thị bên trong hoạt động.


Rất gần :-)
Blundell

Chúng tôi sử dụng thư viện Jetpack Navigation
IgorGanapolsky

1

Trong trường hợp các đoạn được cuộn, khi bạn sử dụng lớp ViewPager, giả sử mVeiwPager, bạn có thể gọi mViewPager.getCienItem () để lấy số int đoạn hiện tại.

trong MainLayout.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical"
    tools:context="unidesign.photo360.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="false"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:expanded="false">

        <android.support.v7.widget.Toolbar
            android:id="@+id/main_activity_toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            app:popupTheme="@style/AppTheme.PopupOverlay"
            app:title="@string/app_name">

        </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>


    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </android.support.v4.view.ViewPager>
    
</android.support.design.widget.CoordinatorLayout>

trong MainActivity.kt

class MainActivity : AppCompatActivity() {
    
        lateinit var mViewPager: ViewPager
        lateinit var pageAdapter: PageAdapter
        
//      ...
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            
            pageAdapter = PageAdapter(supportFragmentManager)
            mViewPager = findViewById(R.id.view_pager)
//          ...
            }
            
        override fun onResume() {
          super.onResume()
          var currentFragment = pageAdapter.getItem(mViewPager.currentItem)
//         ...
          }


1

Tôi thấy findFragmentByTagkhông thuận tiện. Nếu bạn có String currentFragmentTagtrong Activityhoặc cha mẹ của Fragmentbạn, bạn cần lưu nó vào onSaveInstanceStatevà khôi phục nó trong onCreate. Thậm chí nếu bạn làm như vậy, khi Activitytái tạo, onAttachFragmentsẽ gọi trước khi onCreate, vì vậy bạn không thể sử dụng currentFragmentTagtrong onAttachFragment(ví dụ. Cập nhật một số quan điểm dựa trêncurrentFragmentTag ), bởi vì nó có thể chưa phục hồi.

Tôi sử dụng mã sau đây:

Fragment getCurrentFragment() {
    List<Fragment> fragments = getSupportFragmentManager().getFragments();
    if(fragments.isEmpty()) {
        return null;
    }
    return fragments.get(fragments.size()-1);
}

Tài liệu của FragmentManagernhà nước rằng

Thứ tự của các mảnh trong danh sách là thứ tự mà chúng được thêm hoặc đính kèm.

Khi bạn cần làm công cụ dựa trên loại mảnh hiện tại, chỉ cần sử dụng getCurrentFragment() instance of MyFragmentthay vì currentFragmentTag.equals("my_fragment_tag").

Lưu ý rằng getCurrentFragment()trong onAttachFragmentsẽ không nhận được đính kèm Fragment, nhưng đính kèm trước đó.


1

Tôi đã phải làm điều này rất gần đây và không có câu trả lời nào ở đây thực sự phù hợp với kịch bản này.

Nếu bạn tự tin rằng chỉ có một mảnh sẽ hiển thị (toàn màn hình), vì vậy thực sự muốn tìm thấy những gì ở trên cùng của backstack. Ví dụ, như một Kotlincho Fragment:

import androidx.fragment.app.Fragment

fun Fragment.setVisibilityChangeListener(clazz: Class<out Fragment>, listener: (Boolean) -> Unit) {
    fragmentManager?.run {
        addOnBackStackChangedListener {
            val topFragmentTag = getBackStackEntryAt(backStackEntryCount - 1).name
            val topFragment = findFragmentByTag(topFragmentTag)
            listener(topFragment != null && topFragment::class.java == clazz)
        }
    }
}

Và sử dụng nó như:

class MyFragment: Fragment {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        setVisibilityChangeListener(this::class.java) { visible -> 
            // Do stuff
        }
    }
}

1

Bạn cũng có thể làm điều đó rất dễ dàng với một URL trong logcat sẽ chuyển hướng bạn đến mã nguồn của mã nguồn phân đoạn hiện tại. Trước tiên, bạn cần thêm OnBackStackChangedListener trong hoạt động máy chủ như -

activity.getChildFragmentManager().addOnBackStackChangedListener(backStackListener);

Và việc triển khai OnBackStackChangedListener là -

    public FragmentManager.OnBackStackChangedListener backStackListener = () -> {

    String simpleName = "";
    String stackName = getStackTopName().trim();

    if (Validator.isValid(stackName) && stackName.length() > 0) {

      simpleName = stackName.substring(Objects.requireNonNull(stackName).lastIndexOf('.') + 1).trim();

      List<Fragment >
       fragmentList = getChildFragmentManager().getFragments();
      Fragment myCurrentFragment;

      for (int i = 0; i < fragmentList.size(); i++) {
       myCurrentFragment= fragmentList.get(i);
       if (myCurrentFragment.getClass().getSimpleName().equals(simpleName)) {
        //Now you get the current displaying fragment assigned in myCurrentFragment.
        break;
       }
       myFragment = null;
      }
     }


     //The code below is for the source code redirectable logcat which would be optional for you.
     StackTraceElement stackTraceElement = new StackTraceElement(simpleName, "", simpleName + ".java", 50);
     String fileName = stackTraceElement.getFileName();
     if (fileName == null) fileName = "";
     final String info = "Current Fragment is:" + "(" + fileName + ":" +
     stackTraceElement.getLineNumber() + ")";
     Log.d("now", info + "\n\n");
    };

Và phương thức getStackTopName () là -

public String getStackTopName() {
    FragmentManager.BackStackEntry backEntry = null;
    FragmentManager fragmentManager = getChildFragmentManager();
    if (fragmentManager != null) {
        if (getChildFragmentManager().getBackStackEntryCount() > 0)
            backEntry = getChildFragmentManager().getBackStackEntryAt(
                    getChildFragmentManager().getBackStackEntryCount() - 1
            );
    }
    return backEntry != null ? backEntry.getName() : null;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.