2011-03-01 45 views
193

我想將片段添加到以編程方式實現其佈局的活動。我查看了Fragment文檔,但沒有很多例子描述我需要什麼。下面是我試着寫的代碼類型:如何使用以編程方式創建的內容視圖向活動添加片段

public class DebugExampleTwo extends Activity { 

    private ExampleTwoFragment mFragment; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     FrameLayout frame = new FrameLayout(this); 
     if (savedInstanceState == null) { 
      mFragment = new ExampleTwoFragment(); 
      FragmentTransaction ft = getFragmentManager().beginTransaction(); 
      ft.add(frame.getId(), mFragment).commit(); 
     } 

     setContentView(frame); 
    } 
} 

...

public class ExampleTwoFragment extends Fragment { 

    @Override 
    public View onCreateView(LayoutInflater inflater, 
          ViewGroup container, 
          Bundle savedInstanceState) { 
     Button button = new Button(getActivity()); 
     button.setText("Hello There"); 
     return button; 
    } 
} 

此代碼編譯,但在開始崩潰,可能是因爲我的FragmentTransaction.add()不正確。什麼是正確的方法來做到這一點?

回答

167

事實證明,該代碼有多個問題。一個片段不能以這種方式聲明,在與活動相同的java文件中,而不是公共內部類。框架期望片段的構造函數(不帶參數)是公開的和可見的。將片段作爲內部類移動到Activity中,或者爲片段創建新的Java文件修復該片段。

第二個問題是,當你用這種方式添加一個片段時,你必須傳遞一個對包含片段視圖的引用,並且該視圖必須有一個自定義的ID。使用默認ID會導致應用程序崩潰。下面是更新後的代碼:

public class DebugExampleTwo extends Activity { 

    private static final int CONTENT_VIEW_ID = 10101010; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     FrameLayout frame = new FrameLayout(this); 
     frame.setId(CONTENT_VIEW_ID); 
     setContentView(frame, new LayoutParams(
      LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 

     if (savedInstanceState == null) { 
      Fragment newFragment = new DebugExampleTwoFragment(); 
      FragmentTransaction ft = getFragmentManager().beginTransaction(); 
      ft.add(CONTENT_VIEW_ID, newFragment).commit(); 
     } 
    } 

    public static class DebugExampleTwoFragment extends Fragment { 
     @Override 
     public View onCreateView(LayoutInflater inflater, ViewGroup container, 
       Bundle savedInstanceState) { 
      EditText v = new EditText(getActivity()); 
      v.setText("Hello Fragment!"); 
      return v; 
     } 
    } 
} 
+108

如果您只想使用片段作爲活動的頂級內容視圖,那麼您可以使用'ft.add(android.R.id.content,newFragment)'。如果片段的容器不是活動的內容視圖,則只需創建自定義佈局並設置其ID。 – 2011-03-02 00:11:32

+24

而不是硬編碼的id,你可以[定義它在XML](http://developer.android.com/guide/topics/resources/more-resources.html#Id)並引用它爲正常(R.id 。我的身份)。 – 2011-03-02 01:58:22

+0

@JasonHanley如果我將創建許多視圖,你知道我將如何以編程方式生成許多獨特的視圖ID嗎? – 2011-03-03 07:05:26

47

這是我讀Tony Wong's comment後想出了:

public class DebugExampleTwo extends BaseActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     addFragment(android.R.id.content, 
        new DebugExampleTwoFragment(), 
        DebugExampleTwoFragment.FRAGMENT_TAG); 
    } 

} 

...

public abstract class BaseActivity extends Activity { 

    protected void addFragment(@IdRes int containerViewId, 
           @NonNull Fragment fragment, 
           @NonNull String fragmentTag) { 
     getSupportFragmentManager() 
       .beginTransaction() 
       .add(containerViewId, fragment, fragmentTag) 
       .disallowAddToBackStack() 
       .commit(); 
    } 

    protected void replaceFragment(@IdRes int containerViewId, 
            @NonNull Fragment fragment, 
            @NonNull String fragmentTag, 
            @Nullable String backStackStateName) { 
     getSupportFragmentManager() 
       .beginTransaction() 
       .replace(containerViewId, fragment, fragmentTag) 
       .addToBackStack(backStackStateName) 
       .commit(); 
    } 

} 

...

public class DebugExampleTwoFragment extends Fragment { 

    public static final String FRAGMENT_TAG = 
     BuildConfig.APPLICATION_ID + ".DEBUG_EXAMPLE_TWO_FRAGMENT_TAG"; 

    // ... 

} 
4
public abstract class SingleFragmentActivity extends Activity { 

    public static final String FRAGMENT_TAG = "single"; 
    private Fragment fragment; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
     if (savedInstanceState == null) { 
      fragment = onCreateFragment(); 
      getFragmentManager().beginTransaction() 
        .add(android.R.id.content, fragment, FRAGMENT_TAG) 
        .commit(); 
     } else { 
      fragment = getFragmentManager().findFragmentByTag(FRAGMENT_TAG); 
     } 
    } 

    public abstract Fragment onCreateFragment(); 

    public Fragment getFragment() { 
     return fragment; 
    } 

} 

使用

public class ViewCatalogItemActivity extends SingleFragmentActivity { 
    @Override 
    public Fragment onCreateFragment() { 
     return new FragmentWorkShops(); 
    } 

} 
21

閱讀,我想出了ellegant方式,所有的答案後:

public class MyActivity extends ActionBarActivity { 

Fragment fragment ; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    FragmentManager fm = getSupportFragmentManager(); 
    fragment = fm.findFragmentByTag("myFragmentTag"); 
    if (fragment == null) { 
     FragmentTransaction ft = fm.beginTransaction(); 
     fragment =new MyFragment(); 
     ft.add(android.R.id.content,fragment,"myFragmentTag"); 
     ft.commit(); 
    } 

} 

基本不需要添加的FrameLayout作爲片段的容器而不是你可以添加直片段到Android根視圖容器

重要提示:不要使用替換片段作爲大多數的這裏所示的aproach,除非你不介意丟失片段變量在創新過程中的實例狀態。

27
public class Example1 extends FragmentActivity { 

     @Override 
     protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      DemoFragment fragmentDemo = (DemoFragment) 
      getSupportFragmentManager().findFragmentById(R.id.frame_container); 
      //above part is to determine which fragment is in your frame_container 
      setFragment(fragmentDemo); 
         (OR) 
      setFragment(new TestFragment1()); 
     } 

     // This could be moved into an abstract BaseActivity 
     // class for being re-used by several instances 
     protected void setFragment(Fragment fragment) { 
      FragmentManager fragmentManager = getSupportFragmentManager(); 
      FragmentTransaction fragmentTransaction = 
       fragmentManager.beginTransaction(); 
      fragmentTransaction.replace(android.R.id.content, fragment); 
      fragmentTransaction.commit(); 
     } 
    } 

要添加的片段成活動或FramentActivity它需要一個 集裝箱。該容器應該是「Framelayout」,可以是 包含在xml中,或者您可以使用默認容器 (如「android.R.id.content」)來刪除或替換 活動中的片段。

main。xml

<RelativeLayout 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 
<!-- Framelayout to display Fragments --> 
    <FrameLayout 
     android:id="@+id/frame_container" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" /> 

    <ImageView 
     android:id="@+id/imagenext" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentBottom="true" 
     android:layout_alignParentRight="true" 
     android:layout_margin="16dp" 
     android:src="@drawable/next" /> 
</RelativeLayout> 
+1

優秀,節省了我的一天,謝謝 – 2017-02-03 23:32:50

4

對於API等級17或更高的版本,View.generateViewId()將解決此問題。該實用程序方法提供了一個未在構建時使用的唯一標識。

+1

歡迎來到Stack Overflow!雖然這可能會在理論上回答這個問題,[這將是更可取的](// meta.stackoverflow.com/q/8259)在這裏包括答案的基本部分,並提供參考鏈接。 – SuperBiasedMan 2015-09-07 15:53:36

相關問題