2011-07-12 42 views
86

我需要关于片段内部片段的工作方面的帮助,实际上我在按下后退按钮时遇到问题。应用程序主屏幕 有按钮和按下每个按钮视图替换为新的 片段(并且该片段包含在另一片段内), 动态添加/替换片段工作正常,按 替换按钮1片段,按下按钮时也是如此,但如果 我再次按下按钮,有一个例外:片段内部片段

"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: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:id="@+id/linearLayout2" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:orientation="horizontal"></LinearLayout> 
    </LinearLayout> 

希望我试图清除我的问题。

+0

上面的代码工作完全适合我用android 3。1 – Vivek

+3

可能重复的[碎片内的碎片](http://stackoverflow.com/questions/6847460/fragments-within-fragments) – Vladimir

+0

有关更多详细信息,请参阅http://stackoverflow.com/a/11020531/1219456 –

回答

214

AFAIK,片段不能容纳其他片段。


UPDATE

随着Android支持包的最新版本 - 或者天然片段的API等级17和更高 - 你可以窝片段,通过getChildFragmentManager()手段。请注意,这意味着您需要在API级别11-16上使用Android支持包版本的片段,因为即使这些设备上存在片段的本机版本,该版本也没有getChildFragmentManager()

+17

该平台真的很糟糕。我花了三个小时调试它,因为内部片段第一次渲染得很好,但在屏幕方向改变后会消失。没有例外,日志信息,什么都没有。切换到'getChildFragmentManager()'并从内部片段(怜悯)中删除'setRetainInstance(true)'固定它。感谢您再次保存我的培根,@CommonsWare。 – Felix

1

没有支持MapFragment,Android团队说自从Android 3.0以来就开始使用它。这里有关于这个问题的更多信息http://code.google.com/p/android/issues/detail?id=15347&utm_source=buffer&buffer_share=acc72但是你可以通过创建一个返回MapActivity的Fragment来完成。这是一个代码示例。由于inazaruk:https://github.com/inazaruk/examples/tree/master/MapFragmentExample

工作原理:

-MainFragmentActivity是延伸FragmentActivity和主机上的两个MapFragments活动。 -MyMapActivity扩展了MapActivity并具有MapView。 - LocalActivityManagerFragment承载LocalActivityManager。 -MyMapFragment扩展LocalActivityManagerFragment,并在TabHost的帮助下创建MyMapActivity的内部实例。 如果您有任何疑问,请让我知道

10

片段可以添加到其他片段内,但是随后您需要在每次调用父片段的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(); 
    } 
+3

这不适合我。我有一个包含两个子视图的视图的片段。在'onActivityCreated()'中,它使用'getFragmentManager()'将两个片段添加到每个视图中。这是第一次工作,但在轮换和恢复时,只有一个碎片可见。行为与'getChildFragmentManager()'是正确的。这里提出的方法抛出了一个异常,因为活动的'onSaveInstanceState()'已经被调用。使用'commitAllowingStateLoss()'提交事务避免了这个异常,但并没有解决原来的问题。 – user1978019

3

您可以添加FrameLayout的片段和初始化时与另一片段取代它。

这样,您可以考虑将其他片段放在第一个片段中。

0

嗨我解决了这个问题,把每个片段放在不同的layout.And我只是相关的布局可见,并使其他visibilities消失。

我的意思是:

<?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 clicked.You可以控制你的片段对点击action.You能见度可以使相关的布局可见的和其他人走了,由你会打开你的网页片段管理器,你可以把你的片段。这种方法为我工作。并且从视图具有可见性:消失是不可见的,它不需要任何空间用于布局目的我认为这种方法不会导致任何空间问题。

P.S:我只是试图解释我的解决方案代码可能有语法错误或未完成的结构。

7

我解决了这个问题。您可以使用支持库和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; 
} 
} 

P.S.It用于测试丑陋的代码,但它提高了,这是可能的。

P.P.S 内部片段ChildFragmentManager应该传递给ViewPagerAdapter

1

Curently嵌套片段,嵌套一个(或多个)只支持如果程序生成它们!所以目前在xml布局方案中不支持嵌套片段布局!

3

可以使用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) { 


    } 


} 
35

我需要更多的上下文,所以我举了一个例子来说明这是如何完成的。同时准备我读到的最有用的东西是这样的:

活动

activity_main.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"> 

    <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

负载母体片段和实施片段听众。 (见fragment communication。)

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

使用getChildFragmentManageronViewCreated设立子片段。

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

注释
  • 支持库被使用,使得可以nested fragments的Android 4.2之前使用。
+0

它为我工作。 –

1

它没什么复杂的。我们不能在这里使用getFragmentManager()。为了在片段中使用片段,我们使用getChildFragmentManager()。休息将是一样的。