web-dev-qa-db-fra.com

Comment ajouter un fragment à une activité avec une vue de contenu créée par programme

Je souhaite ajouter un fragment à une activité qui implémente sa présentation par programme. J'ai parcouru la documentation de Fragment, mais il n'y a pas beaucoup d'exemples décrivant ce dont j'ai besoin. Voici le type de code que j'ai essayé d'écrire:

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

Ce code est compilé mais se bloque au début, probablement parce que ma FragmentTransaction.add() est incorrecte. Quelle est la bonne façon de faire cela?

219
Tony Wong

Il s'avère qu'il y a plus d'un problème avec ce code. Un fragment ne peut pas être déclaré ainsi, à l'intérieur du même fichier Java que l'activité, mais pas en tant que classe interne publique. Le framework s'attend à ce que le constructeur du fragment (sans paramètre) soit public et visible. Déplacer le fragment dans Activity en tant que classe interne ou créer un nouveau fichier Java pour le fragment corrige ce problème.

Le deuxième problème est que lorsque vous ajoutez un fragment de cette façon, vous devez transmettre une référence à la vue contenant le fragment et cette vue doit avoir un identifiant personnalisé. L'utilisation de l'ID par défaut plantera l'application. Voici le code mis à jour:

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;
        }
    }
}
185
Tony Wong

Voici ce que je suis arrivé après avoir lu commentaire de Tony Wong :

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

    // ...

}

Kotlin

Si vous utilisez Kotlin, assurez-vous de regarder ce que les extensions Kotlin de Google fournissent ou écrivez simplement les vôtres.

61
JJD
    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();
        }
    }

Pour ajouter un fragment à une activité ou à une activité FramentActivity, un conteneur est nécessaire. Ce conteneur doit être un "Framelayout", qui peut être inclus dans le fichier XML. Sinon, vous pouvez utiliser le conteneur par défaut comme "Android.R.id.content" pour supprimer ou remplacer un fragment dans Activity.

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>
31
anand krish

Après avoir lu toutes les réponses, je suis arrivé avec une manière élégante:

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

}

en gros, vous n'avez pas besoin d'ajouter un frameLayout en tant que conteneur de votre fragment. Vous pouvez également ajouter le fragment directement dans le conteneur Android root View.

IMPORTANT: n'utilisez pas replace fragment comme la plupart des méthodes présentées ici, à moins que cela ne vous gêne pas de perdre l'état d'instance de variable fragment au cours du processus de création.

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

}

utilisation

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

}
5
user2212515

Pour le niveau 17 ou supérieur de l'API, View.generateViewId() va résoudre ce problème. La méthode utilitaire fournit un identifiant unique qui n'est pas utilisé lors de la génération.

4
Sfseyhan