J'aimerais savoir comment implémenter un écran de démarrage à l'aide du composant d'architecture de navigation.
Jusqu'à présent, j'ai quelque chose comme ça
Un utilisateur doit configurer son profil dans ProfileFragment
pour la première fois et peut modifier son profil depuis ChatFragment
.
Mon problème est que je ne sais pas comment supprimer SplashFragment
de la pile après la navigation. J'ai vu navigation conditionnelle mais je n'ai pas bien compris.
Je suivrais la réponse de @Sander, si vous avez besoin d’un écran Splash, vous devez le faire correctement - comme décrit ici avec le thème de l’application Splash et sansSplashFragment
. Pour le mettre en œuvre, vous devez disposer d’un minimum de 2 La première activité est SplashActivity
et la seconde est une activité qui hébergera votre NavHostFragment
. Dans Manifest
cela ressemblera à ceci:
<activity Android:name=".ui.SplashActivity"
Android:theme="@style/SplashTheme">
<intent-filter>
<action Android:name="Android.intent.action.MAIN"/>
<category Android:name="Android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity Android:name=".ui.MainActivity"/>
Votre SplashActivity
n'aura qu'une méthode
class SplashActivity : AppCompatActivity() {
override fun onStart() {
super.onStart()
startActivity<MainActivity>()
finishAfterTransition() // use this instead of finish() to prevent flickering when SplashActivity has been finished but MainActivity stil hasnt been initialized
}
}
Après cela, vous accédez à votre activité avec le composant de navigation et cette activité sera la nouvelle racine de votre tâche d'application. Un clic sur Précédent fermera donc l'application . </ S>
J'ai supprimé la solution avec SplashActivity
car elle est redondante, nous pouvons faire tout ce dont nous avons besoin avec une seule activité. Pour mettre en place un écran Splash approprié, suivez this le tutoriel pointé par @Sander . En un mot, pour mettre en place un écran Splash, vous avez besoin de SplashTheme
comme ceci:
<style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
<item name="Android:windowBackground">@drawable/splash_background</item>
</style>
splash_background
drawable devrait être comme ceci:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:opacity="opaque"> <!-- Android:opacity="opaque" should be here -->
<item>
<!--this is your background, you can use color, gradient etc.-->
<color Android:color="@color/colorPrimary"/>
<!--<shape>
<gradient
Android:angle="315"
Android:endColor="#1a82ff"
Android:startColor="#2100d3"
Android:type="linear"/>
</shape> -->
</item>
<item>
<bitmap Android:src="@drawable/ic_logo"
Android:gravity="center"/>
</item>
</layer-list>
Dans la Manifest
, ajoutez simplement SplashTheme
à votre activité:
<activity Android:name=".ui.MainActivity"
Android:theme="@style/SplashTheme">
Puis, dans MainActivity
pour revenir à votre AppTheme
habituelle, faites ceci dans onCreate
avant l'appel super
:
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.AppTheme)
super.onCreate(savedInstanceState)
.....
Les écrans de démarrage ont toujours été étranges sur Android. Vous souhaitez uniquement afficher un écran de démarrage entre le fait de cliquer sur l'icône de l'application et la création de la première Activity
. Si votre écran de démarrage est une Fragment
, l'utilisateur verra toujours le fond blanc jusqu'à la création de la première Activity
et le temps de démarrage de votre application augmentera, car un splash Fragment
devra être créé et supprimé. La meilleure pratique consiste à utiliser une variable AppTheme
, comme l'explique Ian Lake (ingénieur du cadre Android) dans cet article .
En ce qui concerne la navigation, votre application doit avoir une destination fixe qui est le premier et le dernier écran qu'un utilisateur voit lors de son entrée et de sa sortie, comme expliqué dans les principes de navigation . Dans votre cas, il serait logique de définir ChatFragment
comme destination fixe. Dans la onCreate
de la ChatFragment
, vous devriez vérifier si l'utilisateur a déjà un profil et les rediriger vers la ProfileFragment
à l'aide de navigation conditionnelle si ce n'est pas le cas.
Vous pouvez essayer ceci, cela fonctionne actuellement pour moi:
<action
Android:id="@+id/action_splashFragment_to_profileFragment"
app:destination="@id/signInFragment"
app:launchSingleTop="true"
app:popUpTo="@id/splashFragment"
app:popUpToInclusive="true" />
Il suffit de définir popUpTo (la destination actuelle) et popUpToInclusive (true) pour que tous les autres écrans s'affichent jusqu'à ce qu'ils atteignent la destination spécifiée. Indiquez également la destination si popUpToInclusive () est défini sur true avant de naviguer vers la nouvelle destination.
Voici deux façons de résoudre la situation ci-dessus.
One : Dans le NavHostFragment's Activity
, remplacez la méthode onBackPress()
, et si la NavDestination
courante est MainFragment
, alors finish()
la Activity
.
@Override
public void onBackPressed() {
NavDestination navDestination = mNavController.getCurrentDestination();
if (navDestination != null
&& navDestination.getId() == R.id.mainFragment) {
finish();
return;
}
super.onBackPressed();
}
Two: Définissez l'action sur MainFragment dans Navigation_graph app:popUpTo="@id/nav_graph"
et app:popUpToInclusive="true"
<?xml version="1.0" encoding="utf-8"?>
<navigation
Android:id="@+id/nav_graph"
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
app:startDestination="@id/splashFragment">
<fragment
Android:id="@+id/splashFragment"
Android:name="xxx.fragment.splash.SplashFragment"
Android:label="fragment_splash"
tools:layout="@layout/fragment_splash">
<action
Android:id="@+id/action_splashFragment_to_mainFragment"
app:destination="@id/mainFragment"
app:enterAnim="@anim/anim_right_in"
app:exitAnim="@anim/anim_left_out"
app:popEnterAnim="@anim/anim_left_in"
app:popExitAnim="@anim/anim_right_out"
app:popUpTo="@id/nav_graph"
app:popUpToInclusive="true"/>
<action
Android:id="@+id/action_splashFragment_to_guideFragment"
app:destination="@id/guideFragment"
app:enterAnim="@anim/anim_right_in"
app:exitAnim="@anim/anim_left_out"
app:popEnterAnim="@anim/anim_left_in"
app:popExitAnim="@anim/anim_right_out"
app:popUpTo="@id/nav_graph"
app:popUpToInclusive="true"/>
</fragment>
<fragment
Android:id="@+id/guideFragment"
Android:name="xxx.fragment.guide.GuideFragment"
Android:label="GuideFragment"
tools:layout="@layout/fragment_guide">
<action
Android:id="@+id/action_guideFragment_to_mainFragment"
app:destination="@id/mainFragment"
app:enterAnim="@anim/anim_right_in"
app:exitAnim="@anim/anim_left_out"
app:popEnterAnim="@anim/anim_left_in"
app:popExitAnim="@anim/anim_right_out"
app:popUpTo="@id/nav_graph"
app:popUpToInclusive="true"/>
</fragment>
<fragment
Android:id="@+id/mainFragment"
Android:name="xxx.fragment.main.MainFragment"
Android:label="fragment_main"
tools:layout="@layout/fragment_main">
</fragment>
</navigation>
Souhait de l'aide!
Attention: ceci est obsolète. Dans Navigation alpha08, la balise clearTask est supprimée: Supprime les indicateurs clearTask et launchDocument déconseillés de NavOptions
Dans mon projet, je teste l'application: clearTask = "true" dans l'action, et cela fonctionne bien. ~~~
<fragment
Android:id="@+id/splashFragment"
Android:name="xxx.SplashFragment"
Android:label="fragment_splash"
tools:layout="@layout/fragment_splash">
<action
Android:id="@+id/action_splashFragment_to_mainFragment"
app:destination="@id/mainFragment"
app:enterAnim="@anim/anim_right_in"
app:exitAnim="@anim/anim_left_out"
app:popEnterAnim="@anim/anim_left_in"
app:popExitAnim="@anim/anim_right_out"
app:clearTask="true"/>
</fragment>
Vous pouvez essayer cette astuce, ça marche très bien pour moi . Créez votre écran de démarrage en tant qu’écran de lancement à partir du fichier de manifeste et démarrez votre activité d’hôte à partir de cet écran.
Manifest file code
`<activity Android:name=".SplashScreen"
Android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<intent-filter>
<action Android:name="Android.intent.action.MAIN" />
<category Android:name="Android.intent.category.LAUNCHER" />
</intent-filter>
</activity>`
Dans votre fichier Java
`new Handler().postDelayed(new Runnable(){
@Override
public void run() {
/* Create an Intent that will start the Navigation Host activity . */
Intent mainIntent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(mainIntent);
finish();
}
}, 5000);`
Code XML de votre activité d'accueil
`<?xml version="1.0" encoding="utf-8"?>
Android.support.constraint.ConstraintLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
Android:id="@+id/nav_Host_fragment"
Android:name="androidx.navigation.fragment.NavHostFragment"
Android:layout_width="0dp"
Android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/navigation_graph" />
</Android.support.constraint.ConstraintLayout>`
Et votre navigation sera comme ça
`<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/navigation_graph"
app:startDestination="@id/homeFragment"
>
<fragment
Android:id="@+id/homeFragment"
Android:name="com.devgenesis.breaker.ice.navigationmproject.HomeFragment"
Android:label="fragment_home"
tools:layout="@layout/fragment_home" />
</navigation>`