Phân mảnh không được thay thế nhưng được đặt trên phân mảnh trước đó


104

Hoạt động:

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

Fragment1 fragment = new Fragment1();
Fragment2 fragment2 = new Fragment2();

transaction.replace(R.id.Fragment1, fragment);
transaction.addToBackStack(null);
transaction.commit();

FragmentTransaction transaction2 = getSupportFragmentManager().beginTransaction();
transaction2.replace(R.id.Fragment1, fragment2);
transaction2.addToBackStack(null);
transaction2.commit();

Mã trong chế độ xem:

<fragment
    android:id="@+id/Fragment1"
    android:name="com.landa.fragment.Fragment1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_below="@+id/include1" /> 

Vấn đề là, nội dung không thực sự được thay thế - nó được đưa lên trên (vì vậy nó trùng lặp).

Khi tôi nhấp lại, phân đoạn đầu tiên được hiển thị đúng cách (không có phân đoạn thứ hai), nhưng ban đầu cả hai đều hiển thị (tôi chỉ muốn phân đoạn cuối cùng hiển thị).

Tôi còn thiếu gì ở đây?


Trong trường hợp của tôi, sự cố là do thực tế là tôi không sử dụng id thích hợp của chế độ xem vùng chứa, tức là tôi đã không chuyển đúng containerViewId(trong replacephương thức).
nbro

Câu trả lời:


145

Bạn đang làm sai hai điều ở đây:

  1. Bạn không thể thay thế một phân đoạn được đặt tĩnh trong xmltệp bố cục. Bạn nên tạo một vùng chứa (ví dụ a FrameLayout) trong bố cục và sau đó thêm phân đoạn bằng cách sử dụng chương trình FragmentTransaction.

  2. FragmentTransaction.replacemong đợi id của vùng chứa chứa phân đoạn chứ không phải id của phân đoạn làm tham số đầu tiên. Vì vậy, bạn nên chuyển đối số đầu tiên làm id của vùng chứa mà bạn đã thêm phân đoạn đầu tiên vào.

Bạn có thể tham khảo liên kết này để biết thêm chi tiết.


17
Dùng FrameLayoutlàm vật chứa sẽ tốt hơn là sử dụng LinearLayout.
Marcel Bro

3
Sử dụng FrameLayout trống trong Activity cũng giải quyết được vấn đề của tôi
Subtle Fox

1
Nó hoạt động khi làm điều này. Nhưng sau đó khi tôi khởi động ứng dụng của mình và ngay lập tức nhấn nút quay lại, tôi lại rơi vào trạng thái phân mảnh trống, thay vì thoát ứng dụng?
MasterScrat

@MasterScrat Bỏ qua addTobackStack(..)khi thực hiện giao dịch của bạn lần đầu tiên. Điều này sẽ tránh đặt vùng chứa FrameLayout trống vào ngăn xếp phía sau. Bạn sẽ vẫn có thể điều hướng trở lại phân đoạn mà bạn đã thêm.
Alex Meuer

Đây là một video tuyệt vời minh chứng cho lời giải thích của bạn. youtube.com/watch?v=EbcdMxAIr54
SQL và Java Learner

32

Tôi gặp sự cố tương tự nhưng vấn đề của tôi là tôi đang sử dụng hai trình quản lý Fragment khác nhau: Một từ getSupportFragmentManager()và một từ getFragmentManager(). Nếu tôi đã thêm một phân đoạn với SupportFragmentManagervà sau đó thử thay thế phân mảnh đó bằng FragmentManager, thì phân đoạn sẽ chỉ được thêm vào trên cùng. Tôi cần thay đổi mã để FragmentManagersử dụng mã tương tự và điều đó đã giải quyết được vấn đề.


17

Trang web dành cho nhà phát triển android đề xuất việc sử dụng một FrameLayoutđể tải động các phân đoạn tại thời điểm chạy. Bạn đã mã hóa cứng phân đoạn trong tệp xml của mình. Vì vậy, nó không thể bị xóa tại thời điểm chạy như đã đề cập trong liên kết này:

http://developer.android.com/training/basics/fragment/creating.html

liên kết này cho biết cách thêm các đoạn thông qua chương trình của bạn:

http://developer.android.com/training/basics/fragment/fragment-ui.html


7

Tôi đã có cùng một vấn đề và đã xem tất cả các câu trả lời, nhưng không có câu trả lời nào trong số đó có lỗi của tôi! Trước khi cố gắng thay thế phân đoạn hiện tại, tôi đã hiển thị phân đoạn mặc định trong xml của hoạt động vùng chứa như sau:

<FrameLayout
    android:id="@+id/fragment_frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="....ShopFragment"
        android:id="@+id/fragment"
        tools:layout="@layout/fragment_shop" />
</FrameLayout>

sau đó, mặc dù tôi đã chuyển FrameLayoutđến fragmentTransaction.replace()nhưng tôi đã gặp vấn đề chính xác. nó đang hiển thị đoạn thứ hai trên đầu đoạn trước.

Sự cố đã được khắc phục bằng cách xóa phân đoạn khỏi xml và hiển thị nó theo chương trình trong onCreate()phương thức của hoạt động vùng chứa cho bản xem trước mặc định khi bắt đầu chương trình như sau:

    fragmentTransaction = getFragmentManager().beginTransaction();
    fragmentTransaction.replace(R.id.fragment_frame_layout,new ShopFragment());
    fragmentTransaction.addToBackStack(null);
    fragmentTransaction.commit();

và hoạt động vùng chứa xml:

<FrameLayout
    android:id="@+id/fragment_frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

4

Bạn có thể xóa backStack trước khi thay thế các đoạn:

    FragmentManager fm = getActivity().getSupportFragmentManager();

    for (int i = 0; i < fm.getBackStackEntryCount(); i++) {
        fm.popBackStack();
    }

    // replace your fragments

vấn đề là anh ta đã khai báo phân đoạn trong tệp bố cục xml của mình. Do đó nó không thể được gỡ bỏ / thay thế trong thời gian chạy.
Poonam Anthony,

điều này đã hiệu quả với tôi, việc cố gắng thay thế một đoạn mà không xóa backstack dường như để lại mục nhập backstack gần đây nhất trên đầu của bất kỳ đoạn nào khác.
speedynomads

3
<FrameLayout
    android:id="@+id/fragment_frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?android:windowBackground">
//Add fragment here
</FrameLayout>

Thêm android:background="?android:windowBackground">vào vùng chứa chứa phân đoạn của bạn. Trong trường hợp của tôi, tôi đã thêm một FrameLayout, điều đó sẽ hữu ích.


1

Sử dụng vùng chứa thay vì sử dụng phân mảnh

<FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello World!" />

Hiện có trong MainActivity

if(condition)
    getFragmentManager().beginTransaction().replace(R.id.container,new FirstFragment()).commit();                    
else
    getFragmentManager().beginTransaction().replace(R.id.container, new SecondFragment()).commit();

Xin lưu ý rằng lớp phân mảnh của bạn nên nhập 'android.app.Fragment' Đảm bảo rằng bạn sử dụng "support.v4" hoặc triển khai "gốc" và không kết hợp chúng. Tôi nhận được vấn đề này vì tôi đã trộn chúng.


0

Tôi đồng ý với câu trả lời của Sapan Diwakar. Nhưng tôi đã tìm ra một giải pháp về cách thực hiện điều này.

Đầu tiên, trong hoạt động của bạn (ví dụ activity_main), nơi bạn có tất cả các bố cục, Thêm a FrameLayout. Chiều cao và chiều rộng của nó phải là match parent. Ngoài ra, cung cấp cho nó một id.

Bây giờ, trong phân đoạn của bạn sẽ thay thế bố cục hiện tại, hãy gọi onPause()onResume(). Khởi tạo tất cả các thùng chứa bên trong View. Và thiết lập của họ visibilityđể GONEonResume()VISIBLEtrongonPause() .

LƯU Ý : Không phải FrameLayoutcái bạn đang thay thế bằng đoạn này.

Giả sử bạn có ViewPager, TabLayout, ImageViewvà một tùy chỉnh <fragment>trong activity_main.xml. Thêm, một FrameLayoutnhư đã đề cập ở trên.

Trong abcFragment.java, trong onClick()chức năng, thêm addToBackstack(null)vào transaction.

Mã ví dụ:

trong xyzFragment, sẽ thay thế abcFragment (và mọi thứ được hiển thị trong activity_main.xml), hãy làm điều này

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

    // On resume, make everything in activity_main invisible except this fragment.
    slidingTabs = getActivity().findViewById(R.id.sliding_tabs);
    viewPager = getActivity().findViewById(R.id.pager);
    miniPlayerFragment = getActivity().findViewById(R.id.mini_pager);

    slidingTabs.setVisibility(View.GONE);
    viewPager.setVisibility(View.GONE);
    miniPlayerFragment.setVisibility(View.GONE);
}

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

    // Make everything visible again
    slidingTabs = getActivity().findViewById(R.id.sliding_tabs);
    viewPager = getActivity().findViewById(R.id.pager);
    miniPlayerFragment = getActivity().findViewById(R.id.mini_pager);

    slidingTabs.setVisibility(View.VISIBLE);
    viewPager.setVisibility(View.VISIBLE);
    miniPlayerFragment.setVisibility(View.VISIBLE);
}

Chúc bạn viết mã vui vẻ!


0

Bạn có thể sử dụng phương thức setTransition từ FragmentTransaction để khắc phục sự cố chồng chéo.

transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);

0

Trong Oncreate ()

  BaseFragmentloginpage fragment = new BaseFragmentloginpage();
            android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
            fragmentTransaction.replace(R.id.frame, fragment);
            fragmentTransaction.isAddToBackStackAllowed();
            fragmentTransaction.commit();

bây giờ đây sẽ luôn là phân đoạn mặc định của bạn ... nếu bạn thêm phân mảnh trong bố cục xml, nó sẽ luôn chồng chéo lên nhau, vì vậy hãy đặt nội dung ban đầu bằng phân đoạn lúc chạy


0

tôi đã gặp vấn đề tương tự sau khi sử dụng vấn đề này đã được giải quyết

  1. Hãy bố trí khung nơi bạn đang thay thế phân đoạn của bạn

    <FrameLayout
                    android:id="@+id/fragment_place"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
  2. và mã để thay thế

    public void selectFrag(View view) {
    Fragment fr;
    
      if(view == findViewById(R.id.button2))
    {
         fr = new FragmentTwo();
    
     }else {
         fr = new FragmentOne();
     }
     FragmentManager fm = getFragmentManager();
     FragmentTransaction fragmentTransaction = fm.beginTransaction();
     fragmentTransaction.replace(R.id.fragment_place, fr);
     fragmentTransaction.commit();

nếu bạn muốn toàn bộ ví dụ, tôi sẽ gửi cho bạn chỉ cần nhận xét tôi ......


0

Tôi cũng gặp vấn đề tương tự, nhưng đó là vì tôi đã không thay đổi màu nền của đoạn mà tôi đang cố gắng thêm vào khung hình của mình.

Hãy thử làm điều này, với layout_heightlayout_widthđặt thànhmatch_parent


0

Tôi đã từng gặp sự cố này và phát hiện ra rằng đó là do tôi đã vô tình xóa android:backgroundthuộc tính bị thiếu trên mã xml của bạn. Tôi tin rằng nó hoạt động giống như khi bạn sơn một bức tường, android:backgroundlà màu của bức tường đó và các góc nhìn khác được đặt lên trên màu cơ bản đó. Khi bạn không sơn bức tường trước khi định vị khung nhìn của mình, chúng sẽ ở trên những gì đã có trong bức tường đó, trong trường hợp của bạn là mảnh vỡ khác của bạn. Không biết điều đó có giúp ích được gì cho bạn không, chúc bạn may mắn.


0

Tôi đã thử trên tất cả các trường hợp và cố gắng khắc phục sự cố nhưng vẫn không có giải pháp. Tôi không biết tại sao nó không hoạt động với tôi. Tôi đồng ý với những câu trả lời trên vì rất nhiều người đồng ý với nó.

Tôi chỉ mở rộng câu trả lời và dưới đây là cách làm việc cho tôi.

Tôi đã thêm android:clickable="true"thuộc tính này trong bố cục mẹ trên cùng trong fragment.xmlhồ sơ.

Tôi hy vọng ai đó sẽ nhận được sự giúp đỡ.


0

Xin cảm ơn Sapan Diwakar và những người khác. Câu trả lời này đã giúp tôi. Tôi chỉ đơn giản tạo một RelativeLayout mà không có phân đoạn bên trong nó, sử dụng RelativeLayout làm chế độ xem mẹ hoặc nhóm, chỉ định chế độ xem nhóm đó trong giao dịch để thay thế và nó đã hoạt động.

Mã:

getSupportFragmentManager().beginTransaction()
                            .replace(R.id.content_group_view, itemDetailFragment).commit();

XML:

 <RelativeLayout
         android:id="@+id/content_group_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent">

 </RelativeLayout>

0

Kiểm tra ID bố cục khung của bạn và thay thế nó như bên dưới

fragmentTransactionChange = MainActivity.this.getSupportFragmentManager().beginTransaction();
fragmentTransactionChange.replace(R.id.progileframe, changeFragment);
fragmentTransactionChange.addToBackStack(null);
fragmentTransactionChange.commit();
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.