Как добавить фрагмент в действие с помощью программно созданного представления содержимого
Я хочу добавить фрагмент к действию, которое реализует его макет программно. Я посмотрел фрагмент документации, но там не так много примеров, описывающих то, что мне нужно. Вот тип кода, который я пытался написать:
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()
некорректно. Как правильно это сделать?
6 ответов:
оказывается, есть более чем одна проблема с этим кодом. Фрагмент не может быть объявлен таким образом, внутри того же файла java, что и activity, но не как открытый внутренний класс. Фреймворк ожидает, что конструктор фрагмента (без параметров) будет общедоступным и видимым. Перемещение фрагмента в действие как внутренний класс или создание нового файла java для фрагмента исправляет это.
вторая проблема заключается в том, что когда вы добавляете фрагмент таким образом, вы должны пройти ссылка на содержащее фрагмент представление, и это представление должно иметь пользовательский идентификатор. Использование идентификатора по умолчанию приведет к сбою приложения. Вот обновленный код:
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; } } }
вот что я придумал после прочтения комментарий Тони Вонга:
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"; // ... }
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
" для удаления или замены фрагмента в Деятельность.главная.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>
после того, как прочитал все ответы, я придумал элегантный способ:
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
важно: не используйте заменить фрагмент как и большинство показанных здесь приближений, если вы не возражаете потерять состояние экземпляра переменной фрагмента во время процесса onrecreation.
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(); } }
для уровня API 17 или выше,вид.generateViewId () решит эту проблему. Метод, программа предоставляет уникальный идентификатор, который не используется во время сборки.