조각 내부 조각


137

조각 내부의 조각 작업에 관한 도움이 필요합니다. 실제로 뒤로 버튼을 누르는 데 문제가 있습니다. 응용 프로그램 메인 화면에는 버튼이 있으며 각 버튼보기를 누르면 새 조각으로 바뀝니다 (그리고 그 조각에는 다른 조각 안에 포함되어 있음), 조각을 동적으로 추가 / 교체하는 것은 정상적으로 작동합니다. 버튼은 다시 예외가 발생했습니다.

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

조각 또는 내부 조각이 이미 추가되어 다시 추가하려고한다는 것을 의미합니다. 아무도 조각 덕분에 조각 내부 조각으로 작업하고 문제없이 앞뒤로 움직이는 방법을 알고 있습니다.

MainActivity. 조각이 동적으로 추가 및 교체됩니다.

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

레이아웃은 다음과 같습니다. 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>

내 문제를 해결하려고 노력했습니다.


1
위의 코드는 안드로이드 3.1에서 완벽하게 작동합니다
Vivek


답변:


284

AFAIK, 단편은 다른 단편을 보유 할 수 없습니다.


최신 정보

현재 버전의 Android 지원 패키지 또는 API 레벨 17 이상의 기본 단편을 사용하면을 통해 단편을 중첩 할 수 있습니다 getChildFragmentManager(). 이는 기기에 기본 버전의 프래그먼트가 있지만 해당 버전에는이 버전이 없기 때문에 API 레벨 11-16에서 Android 지원 패키지 버전의 프래그먼트를 사용해야 함을 의미합니다 getChildFragmentManager().


30
이 플랫폼은 정말 짜증납니다. 내부 조각이 처음에는 잘 렌더링되지만 화면 방향이 변경된 후에 사라지기 때문에 이것을 디버깅하는 데 3 시간이 걸렸습니다 . 예외도없고, 로그 정보도 없습니다. 내부 단편 (연동)으로 전환하여 getChildFragmentManager()제거 setRetainInstance(true)했습니다. @CommonsWare를 다시 저장해 주셔서 감사합니다.
Felix

82

여기에 이미지 설명을 입력하십시오

더 많은 컨텍스트가 필요했기 때문에 이것이 어떻게 수행되는지 보여주는 예제를 만들었습니다. 준비하는 동안 가장 도움이되는 것은 다음과 같습니다.

활동

activity_main.xml

FrameLayout부모 조각을 보유하려면 활동에 a 를 추가하십시오 .

<?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

부모 프래그먼트를로드하고 프래그먼트 리스너를 구현하십시오. 단편 통신을 참조하십시오 .

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

부모 조각

fragment_parent.xml

FrameLayout자식 조각에 대한 다른 컨테이너를 추가하십시오 .

<?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

사용 getChildFragmentManager에서이 onViewCreated하위 조각을 설정합니다.

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

아동 조각

fragment_child.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:layout_margin="20dp"
              android:background="#f1ff91">

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

ChildFragment.java

여기에는 너무 특별한 것도 없습니다.

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

노트

  • 지원 라이브러리는 Android 4.2 이전에 중첩 된 조각을 사용할 수 있도록 사용되고 있습니다.


13

조각은 다른 조각 안에 추가 할 수 있지만 부모 조각의 onDestroyView()메서드가 호출 될 때마다 부모 조각에서 조각을 제거해야합니다 . 그리고 다시 Parent Fragment의 onCreateView()방법으로 추가하십시오 .

그냥 이렇게하십시오 :

@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
이것은 나를 위해 작동하지 않았습니다. 두 개의 어린이 뷰가 포함 된 뷰를 팽창시킨 조각이 있습니다. 여기에서를 사용하여 onActivityCreated()두 개의 프래그먼트를 각 뷰에 하나씩 추가했습니다 getFragmentManager(). 이것은 처음에는 효과가 있었지만 회전 및 재개시 조각 중 하나만 표시되었습니다. getChildFragmentManager()대신 동작이 정확했습니다 . 활동 onSaveInstanceState()이 이미 호출되었으므로 여기에서 제안한 접근 방식에서 예외가 발생했습니다 . 트랜잭션을 커밋하여 commitAllowingStateLoss()예외 를 피했지만 원래 문제는 해결하지 못했습니다.
user1978019

8

이 문제를 해결했습니다. 지원 라이브러리 및을 사용할 수 있습니다 ViewPager. 제스처로 스 와이프 할 필요가없는 경우 스 와이프를 사용 중지 할 수 있습니다. 내 솔루션을 향상시키는 코드는 다음과 같습니다.

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

PS 테스트를위한 추악한 코드이지만 가능하다는 것을 향상시킵니다.

PPS 내부 조각 ChildFragmentManagerViewPagerAdapter


8

getChildFragmentManager()기능 을 사용할 수 있습니다 .

예:

부모 조각 :

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

부모 레이아웃 ( 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>

아동 조각 :

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

복잡하지 않습니다. getFragmentManager()여기서 사용할 수 없습니다 . Fragment 안에서 Fragments 를 사용하기 위해 우리는 사용 getChildFragmentManager()합니다. 나머지는 동일합니다.


3

FrameLayout조각을 추가 하고 초기화 할 때 다른 조각으로 바꿀 수 있습니다 .

이 방법으로 다른 조각이 첫 번째 조각 안에 있다고 생각할 수 있습니다.



2

중첩 된 조각에서 현재 중첩 된 것은 프로그래밍 방식으로 생성 된 경우에만 지원됩니다! 따라서 현재 xml 레이아웃 체계에서 중첩 조각 레이아웃이 지원되지 않습니다!


1

Kotlin에서 일하는 사람들에게 확장 기능을 사용할 수 있으므로 kotlin 파일을 만들고 "util.kt"라고 말하고이 코드를 추가하십시오

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

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

이것이 어린이 의 클래스라고 가정 해 봅시다.

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)
        ...
    }
    ...
}

이제 이런 식으로 아버지 조각에 아이들을 추가 할 수 있습니다

 FatherPresentation:Fragment()
{
  ...

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

여기서 R.id.fragmet_field 는 조각을 포함 할 레이아웃의 id입니다.이 lyout은 물론 father 조각 안에 있습니다. 여기에 예가 있습니다

father_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

에 대한 지원은 없습니다 MapFragment.Android 팀은 Android 3.0부터 작업하고 있다고 말합니다. 여기 에 문제에 대한 자세한 정보가 있지만를 반환하는 Fragment를 만들어서 할 수있는 작업은 다음과 같습니다MapActivity . 여기 은 코드 예입니다. inazaruk 덕분에 :

작동 방식 :

  • MainFragmentActivity는 FragmentActivity두 개의 MapFragments 를 확장 하고 호스팅 하는 활동입니다 .
  • MyMapActivity는 MapActivity를 확장하고 MapView.
  • LocalActivityManagerFragment LocalActivityManager를 호스팅합니다.
  • MyMapFragment가 확장 LocalActivityManagerFragment되고 MyMapActivity의 TabHost내부 인스턴스가 만들어집니다.

궁금한 점이 있으면 알려주세요.


0

안녕 나는 조각 당 별개의 레이아웃에 넣어이 문제를 해결하고 관련 레이아웃을 보이게하고 다른 가시성을 사라지게했습니다.

내말은:

<?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>

버튼 1을 클릭하면 페이지가 열릴 것이라고 가정했습니다. 클릭 동작에서 조각의 가시성을 제어 할 수 있습니다. 관련 레이아웃을 표시하고 다른 레이아웃을 사라지게하고 조각 관리자를 통해 조각을 가져올 수 있습니다.이 접근법은 저에게 효과적이었습니다. 그리고 가시성이있는보기 : 사라졌고 레이아웃 목적으로 공간을 차지하지 않기 때문에이 접근법은 공간 문제를 일으키지 않는다고 생각합니다.

추신 : 방금 솔루션 코드에 구문 오류가 있거나 구조가 완료되지 않았 음을 설명하려고했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.