Mảnh vỡ bên trong mảnh vỡ


137

Tôi cần giúp đỡ về việc làm việc trên mảnh vỡ bên trong mảnh vỡ, thực sự tôi đang gặp phải một vấn đề khi nhấn nút quay lại. Ứng dụng Màn hình chính có các nút và nhấn vào mỗi chế độ xem nút thay thế bằng đoạn mới (và đoạn đó chứa bên trong một đoạn khác), tự động thêm / thay thế đoạn đó hoạt động tốt, bằng cách nhấn nút1 thay thế, điều tương tự xảy ra khi nhấn nút, nhưng nếu tôi nhấn nút một lần nữa, có một ngoại lệ:

"Duplicate id 0x7f05000a, tag null, or parent id 0x7f050009 with
another fragment for com........ fragmentname"

có nghĩa là mảnh vỡ hoặc mảnh vỡ bên trong đã được thêm vào và tôi đang cố gắng thêm chúng một lần nữa, bất kỳ ai cũng có ý tưởng làm thế nào với mảnh vỡ bên trong mảnh vỡ và di chuyển qua lại mà không gặp vấn đề gì, cảm ơn sự hỗ trợ.

MainActivity, nơi các mảnh được động và thêm vào.

public class FragmentInsideFragmentTestActivity extends Activity {

    private Button button1;
    private Button button2;
    private Button button3;
    private Button button4;


    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        button1 =(Button) this.findViewById(R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
           public void onClick(View view) {
               onButtonClick(view);
            }
        });

        button2 =(Button) this.findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                onButtonClick(view);
            }
        });

        button3 =(Button) this.findViewById(R.id.button3);
        button3.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
               onButtonClick(view);
            }
        });

        button4 =(Button) this.findViewById(R.id.button4);
        button4.setOnClickListener(new View.OnClickListener() {
           public void onClick(View view) {
               onButtonClick(view);
           }
        });
    }

    public void onButtonClick(View v) {
        Fragment fg;

        switch (v.getId()) {
           case R.id.button1:
                   fg=FirstFragment.newInstance();
                   replaceFragment(fg);
                   break;
           case R.id.button2:
                   fg=SecondFragment.newInstance();
                   replaceFragment(fg);
                   break;
           case R.id.button3:
                   fg=FirstFragment.newInstance();
                   replaceFragment(fg);
                   break;
           case R.id.button4:
                   fg=SecondFragment.newInstance();
                   replaceFragment(fg);
                   break;
        }
    }

    private void replaceFragment(Fragment newFragment) {
       FragmentTransaction trasection = getFragmentManager().beginTransaction();

        if(!newFragment.isAdded()) {
            try {
                //FragmentTransaction trasection =
                getFragmentManager().beginTransaction();
                trasection.replace(R.id.linearLayout2, newFragment);
                trasection.addToBackStack(null);
                trasection.commit();
            } catch (Exception e) {
                // TODO: handle exception
                // AppConstants.printLog(e.getMessage());
            } else {
                trasection.show(newFragment);
            }
        }
    }

Đây là Bố cục: main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button1" />

        <Button
            android:id="@+id/button2"
            android:text="Button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <Button
            android:id="@+id/button3"
            android:text="Button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <Button
            android:id="@+id/button4"
            android:text="Button4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/linearLayout2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" />
</LinearLayout>

Hy vọng tôi đã cố gắng để giải quyết vấn đề của tôi.


1
Mã trên đang hoạt động hoàn toàn tốt đối với tôi với Android 3.1
Vivek

3
bản sao có thể của các mảnh vỡ trong các mảnh vỡ
Vladimir

để biết thêm chi tiết tham khảo stackoverflow.com/a/11020531/1219456
Raneez Ahmed

Câu trả lời:


284

AFAIK, các mảnh vỡ không thể giữ các mảnh khác.


CẬP NHẬT

Với các phiên bản hiện tại của gói Hỗ trợ Android - hoặc các đoạn gốc trên API Cấp 17 trở lên - bạn có thể lồng các đoạn, bằng cách getChildFragmentManager(). Lưu ý rằng điều này có nghĩa là bạn cần sử dụng phiên bản gói Hỗ trợ Android trên các cấp API 11-16, bởi vì mặc dù có phiên bản phân đoạn gốc trên các thiết bị đó, nhưng phiên bản đó không có getChildFragmentManager().


30
Nền tảng thực sự hút ở đây. Tôi đã dành ba giờ để gỡ lỗi này vì lần đầu tiên bên trong sẽ hiển thị tốt, nhưng sẽ biến mất sau khi thay đổi hướng màn hình. Không có ngoại lệ, thông tin đăng nhập, không có gì. Chuyển sang getChildFragmentManager()và loại bỏ setRetainInstance(true)từ mảnh bên trong (thương hại) đã cố định nó. Cảm ơn vì đã cứu thịt xông khói của tôi một lần nữa, @CommonsWare.
Felix

82

nhập mô tả hình ảnh ở đây

Tôi cần thêm một số bối cảnh, vì vậy tôi đã làm một ví dụ để cho thấy cách thức này được thực hiện. Điều hữu ích nhất tôi đọc được trong khi chuẩn bị là:

Hoạt động

Activity_main.xml

Thêm một FrameLayoutvào hoạt động của bạn để giữ đoạn cha mẹ.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Activity"/>

    <FrameLayout
        android:id="@+id/parent_fragment_container"
        android:layout_width="match_parent"
        android:layout_height="200dp"/>

 </LinearLayout>

MainActivity.java

Tải đoạn cha mẹ và thực hiện các trình nghe đoạn. (Xem thông tin liên lạc đoạn .)

import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity implements ParentFragment.OnFragmentInteractionListener, ChildFragment.OnFragmentInteractionListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Begin the transaction
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.parent_fragment_container, new ParentFragment());
        ft.commit();
    }

    @Override
    public void messageFromParentFragment(Uri uri) {
        Log.i("TAG", "received communication from parent fragment");
    }

    @Override
    public void messageFromChildFragment(Uri uri) {
        Log.i("TAG", "received communication from child fragment");
    }
}

Mảnh vỡ của cha mẹ

Fragment_parent.xml

Thêm một FrameLayoutcontainer khác cho các mảnh con.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:layout_margin="20dp"
              android:background="#91d0c2">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Parent fragment"/>

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

    </FrameLayout>

</LinearLayout>

ParentFragment.java

Sử dụng getChildFragmentManagertrong onViewCreatedthiết lập các đoạn đứa trẻ.

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;    

public class ParentFragment extends Fragment {

    private OnFragmentInteractionListener mListener;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_parent, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        Fragment childFragment = new ChildFragment();
        FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
        transaction.replace(R.id.child_fragment_container, childFragment).commit();
    }


    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        void messageFromParentFragment(Uri uri);
    }
}

Mảnh vỡ trẻ em

Fragment_child.xml

Không có gì đặc biệt ở đây.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:layout_margin="20dp"
              android:background="#f1ff91">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Child fragment"/>
</LinearLayout>

ChildFragment.java

Không có gì quá đặc biệt ở đây cả.

import android.support.v4.app.Fragment;

public class ChildFragment extends Fragment {

    private OnFragmentInteractionListener mListener;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_child, container, false);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }


    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        void messageFromChildFragment(Uri uri);
    }
}

Ghi chú

  • Thư viện hỗ trợ đang được sử dụng để các đoạn lồng nhau có thể được sử dụng trước Android 4.2.


13

Các mảnh vỡ có thể được thêm vào bên trong các mảnh khác nhưng sau đó bạn sẽ cần phải loại bỏ nó khỏi cha mẹ Mảnh vỡ mỗi khi onDestroyView()phương thức của đoạn cha mẹ được gọi. Và một lần nữa thêm nó vào onCreateView()phương pháp của Parent Fragment .

Chỉ cần làm như thế này:

@Override
    public void onDestroyView()
    {
                FragmentManager mFragmentMgr= getFragmentManager();
        FragmentTransaction mTransaction = mFragmentMgr.beginTransaction();
                Fragment childFragment =mFragmentMgr.findFragmentByTag("qa_fragment")
        mTransaction.remove(childFragment);
        mTransaction.commit();
        super.onDestroyView();
    }

4
Điều này đã không làm việc cho tôi. Tôi đã có một đoạn làm tăng một khung nhìn chứa hai khung nhìn của trẻ em. Trong onActivityCreated()đó thêm hai mảnh, một mảnh vào mỗi khung nhìn, sử dụng getFragmentManager(). Điều này đã làm việc lần đầu tiên, nhưng khi quay và tiếp tục chỉ có một trong những mảnh vỡ được nhìn thấy. getChildFragmentManager()Thay vào đó, hành vi đã đúng . Cách tiếp cận được đề xuất ở đây đã đưa ra một ngoại lệ vì hoạt động onSaveInstanceState()này đã được gọi. Cam kết giao dịch sử dụng commitAllowingStateLoss()tránh ngoại lệ nhưng không giải quyết được vấn đề ban đầu.
dùng1978019

8

Tôi đã giải quyết vấn đề này. Bạn có thể sử dụng thư viện Hỗ trợ và ViewPager. Nếu bạn không cần vuốt bằng cử chỉ, bạn có thể tắt thao tác vuốt. Vì vậy, đây là một số mã để cải thiện giải pháp của tôi:

public class TestFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.frag, container, false);
    final ArrayList<Fragment> list = new ArrayList<Fragment>();

    list.add(new TrFrag());
    list.add(new TrFrag());
    list.add(new TrFrag());

    ViewPager pager = (ViewPager) v.findViewById(R.id.pager);
    pager.setAdapter(new FragmentPagerAdapter(getChildFragmentManager()) {
        @Override
        public Fragment getItem(int i) {
            return list.get(i);
        }

        @Override
        public int getCount() {
            return list.size();
        }
    });
    return v;
}
}

PSIt là mã xấu để thử nghiệm, nhưng nó cải thiện rằng nó có thể.

PPS Inside đoạn ChildFragmentManagernên được chuyển đếnViewPagerAdapter


8

bạn có thể sử dụng getChildFragmentManager()chức năng.

thí dụ:

Đoạn cha mẹ:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    rootView = inflater.inflate(R.layout.parent_fragment, container,
            false);


    }

    //child fragment 
    FragmentManager childFragMan = getChildFragmentManager();
    FragmentTransaction childFragTrans = childFragMan.beginTransaction();
    ChildFragment fragB = new ChildFragment ();
    childFragTrans.add(R.id.FRAGMENT_PLACEHOLDER, fragB);
    childFragTrans.addToBackStack("B");
    childFragTrans.commit();        


    return rootView;
}

Bố trí phụ huynh ( parent_fragment.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white">



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




</LinearLayout>

Mảnh vỡ trẻ em:

public class ChildFragment extends Fragment implements View.OnClickListener{

    View v ;
    @Override
    public View onCreateView(LayoutInflater inflater,
                             @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        View rootView = inflater.inflate(R.layout.child_fragment, container, false);


        v = rootView;


        return rootView;
    }



    @Override
    public void onClick(View view) {


    }


} 

4

Không có gì phức tạp. Chúng tôi không thể sử dụng getFragmentManager()ở đây. Để sử dụng Fragment bên trong Fragment , chúng tôi sử dụng getChildFragmentManager(). Nghỉ ngơi sẽ giống nhau.


3

Bạn có thể thêm FrameLayoutvào đoạn và thay thế nó bằng đoạn khác khi nó khởi tạo.

Bằng cách này, bạn có thể coi mảnh kia nằm trong mảnh đầu tiên.



2

Tò mò trong các đoạn lồng nhau, (các) lồng nhau chỉ được hỗ trợ nếu chúng được tạo lập trình! Vì vậy, tại thời điểm này, không có bố cục phân đoạn lồng nhau nào được hỗ trợ trong sơ đồ bố trí xml!


1

Điều đó có thể giúp những người làm việc trên Kotlin, bạn có thể sử dụng chức năng mở rộng, vì vậy hãy tạo tệp kotlin, hãy nói "produc.kt" và thêm đoạn mã này

fun Fragment.addChildFragment(fragment: Fragment, frameId: Int) {

    val transaction = childFragmentManager.beginTransaction()
    transaction.replace(frameId, fragment).commit()
}

Hãy nói rằng đây là lớp học của đứa trẻ

class InputFieldPresentation: Fragment()
{
    var views: View? = null
    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        views = inflater!!.inflate(R.layout.input_field_frag, container, false)
        return views
    }

    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        ...
    }
    ...
}

Bây giờ bạn có thể thêm các con vào đoạn cha như thế này

 FatherPresentation:Fragment()
{
  ...

    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val fieldFragment= InputFieldPresentation()
        addChildFragment(fieldFragment,R.id.fragmet_field)
    }
...
}

Trong đó R.id.fragmet_field là id của bố cục sẽ chứa đoạn này. Tất nhiên phần này nằm trong đoạn cha. Đây là một ví dụ

cha_fragment.xml :

<LinearLayout android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android"
    >

    ...

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:id="@+id/fragmet_field"
            android:orientation="vertical"
            >
        </LinearLayout>
    ...

    </LinearLayout>

1

Không có hỗ trợ cho MapFragment, nhóm Android cho biết đang làm việc trên nó kể từ Android 3.0. Ở đây có thêm thông tin về vấn đề Nhưng những gì bạn có thể làm bằng cách tạo một Mảnh vỡ trả về a MapActivity. Đây là một ví dụ mã. Cảm ơn inazaruk:

Làm thế nào nó hoạt động :

  • MainFragmentActivity là hoạt động mở rộng FragmentActivityvà lưu trữ hai MapFragments.
  • MyMapActivity mở rộng MapActivity và có MapView.
  • LocalActivityManagerFragment lưu trữ LocalActivityManager.
  • MyMapFragment mở rộng LocalActivityManagerFragmentvà với sự trợ giúp của việc TabHosttạo phiên bản nội bộ của MyMapActivity.

Nếu bạn có bất kỳ nghi ngờ xin vui lòng cho tôi biết


0

Xin chào Tôi đã giải quyết vấn đề này bằng cách đặt mỗi Fragment vào bố cục riêng biệt. Và tôi đã hiển thị Bố cục liên quan và làm cho các hình ảnh khác biến mất.

Ý tôi là:

<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent">

     <LinearLayout android:id="@+id/linearLayout1"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:orientation="horizontal">
           <Button android:layout_width="wrap_content"
                   android:id="@+id/button1"
                   android:layout_height="wrap_content"
                   android:text="Button1"></Button>
           <Button android:text="Button2"
                   android:id="@+id/button2"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"></Button>
           <Button android:text="Button3"
                   android:id="@+id/button3"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"></Button>
           <Button android:text="Button4"
                   android:id="@+id/button4"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"></Button>
   </LinearLayout>
   <LinearLayout android:layout_width="full_screen"
              android:layout_height="0dp"
              android:layout_weight="1"
              android:id="action_For_Button1"
              android:visibility="visible">
                    <Fragment android:layout_width="full_screen"
                              android:layout_height="full_screen"
                              android:id="fragment1"
                                        .
                                        .
                                        .
             / >
     </LinearLayout>

     <LinearLayout android:layout_width="full_screen"
              android:layout_height="0dp"
              android:id="action_For_Button1"
              android:layout_weight="1"
              android:visibility="gone">
                       <Fragment android:layout_width="full_screen"
                                 android:layout_height="full_screen"
                                 android:id="fragment2"
                                           .
                                           .
                                           .
             / >
        </LinearLayout>
                     .
                     .
                     .
        </LinearLayout>

Tôi giả định rằng bạn sẽ mở trang của mình khi nhấp vào nút 1. Bạn có thể kiểm soát mức độ hiển thị của mảnh vỡ của mình trên hành động nhấp chuột. Bạn có thể hiển thị Bố cục liên quan và những người khác biến mất và bằng Trình quản lý mảnh, bạn có thể lấy đoạn của mình. Và vì chế độ xem có khả năng hiển thị: biến mất là vô hình và nó không chiếm bất kỳ không gian nào cho mục đích bố trí, tôi nghĩ cách tiếp cận này không gây ra bất kỳ vấn đề không gian nào.

PS: Tôi chỉ cố gắng giải thích mã giải pháp của tôi có thể có lỗi cú pháp hoặc cấu trúc chưa hoàn thành.

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.