web-dev-qa-db-fra.com

Android: autoriser portrait et paysage pour les tablettes, mais forcer portrait sur téléphone?

Je souhaite que les tablettes puissent être affichées en portrait et en paysage (sw600dp ou supérieur), mais que les téléphones soient limités à portrait. Je ne trouve aucun moyen de choisir conditionnellement une orientation. Aucune suggestion?

177
Kenny Wyland

Voici un bon moyen d'utiliser ressources _ et qualificateurs de taille .

Mettez cette ressource bool dans res/values ​​sous la forme bools.xml ou autre (les noms de fichiers n’importent pas ici):

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <bool name="portrait_only">true</bool>
    </resources>

Mettez celui-ci dans res/values-sw600dp et res/values-xlarge:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <bool name="portrait_only">false</bool>
    </resources>

Voir cette réponse supplémentaire _ pour obtenir de l'aide sur l'ajout de ces répertoires et fichiers dans Android Studio.

Ensuite, dans la méthode onCreate de vos activités, vous pouvez le faire:

    if(getResources().getBoolean(R.bool.portrait_only)){
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }

Les appareils de plus de 600 dp dans le sens de la largeur le plus petit ou x-large sur les appareils antérieurs à Android 3.2 (essentiellement les tablettes) se comporteront comme d'habitude, basé sur le capteur et la rotation verrouillée par l'utilisateur, etc. . Tout le reste (les téléphones, à peu près) ne sera que portrait.

417
Brian Christensen

Vous pouvez essayer de cette façon d'abord obtenir la taille de l'écran de l'appareil 

if ((getResources().getConfiguration().screenLayout &      Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) {     
    Toast.makeText(this, "Large screen",Toast.LENGTH_LONG).show();

}
else if ((getResources().getConfiguration().screenLayout &      Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_NORMAL) {     
    Toast.makeText(this, "Normal sized screen" , Toast.LENGTH_LONG).show();

} 
else if ((getResources().getConfiguration().screenLayout &      Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_SMALL) {     
    Toast.makeText(this, "Small sized screen" , Toast.LENGTH_LONG).show();
}
else {
    Toast.makeText(this, "Screen size is neither large, normal or small" , Toast.LENGTH_LONG).show();
}

puis définir l'orientation en fonction de celle 

setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
28
Avi Kumar Manku

Voici comment je l'ai fait (inspiré par http://androidblogger.blogspot.com/2011/08/orientation-for-both-phones-and-tablets.html ):

Dans AndroidManifest.xml, pour chaque activité que vous souhaitez pouvoir basculer entre portrait et paysage (assurez-vous d'ajouter screenSize - vous n'en aviez pas besoin auparavant!). Vous n'avez pas besoin de définir l'orientation de l'écran ici. :

Android:configChanges="keyboardHidden|orientation|screenSize"

Méthodes à ajouter à chaque activité:

public static boolean isXLargeScreen(Context context) {
    return (context.getResources().getConfiguration().screenLayout
    & Configuration.SCREENLAYOUT_SIZE_MASK)
    >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
} 

et: (si vous ne remplacez pas cette méthode, l'application appellera onCreate () lors du changement d'orientations)

@Override
public void onConfigurationChanged (Configuration newConfig)
{       
    super.onConfigurationChanged(newConfig);

    if (!isXLargeScreen(getApplicationContext()) ) {            
        return; //keep in portrait mode if a phone      
    }

    //I set background images for landscape and portrait here
}

Dans onCreate () de chaque activité:

if (!isXLargeScreen(getApplicationContext())) { //set phones to portrait; 
   setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);            
}
else {
  //I set background images here depending on portrait or landscape orientation 
}

La seule chose que je n'arrive pas à comprendre, c'est comment faire en sorte que l'application modifie les fichiers de présentation lors du passage de paysage à portrait ou vice versa. Je suppose que la réponse consiste à faire quelque chose de similaire à ce que fait le lien ci-dessus, mais je ne pouvais pas le faire fonctionner pour moi - cela supprimait toutes mes données. Mais si vous avez une application assez simple et que vous avez le même fichier de présentation pour portrait et paysage, cela devrait fonctionner.

8
Ginny

Supplément à la réponse acceptée

Vous pouvez effectuer les étapes suivantes dans Android Studio pour ajouter les répertoires res/values-sw600dp et res/values-large à leurs fichiers bools.xml.

valeurs-sw600dp

Tout d'abord, dans l'onglet Projet, sélectionnez le filtre Projet (plutôt qu'Android) dans le navigateur.

enter image description here

Puis cliquez avec le bouton droit sur le répertoire app/src/main/res. Choisissez Nouveau> Répertoire des ressources Android.

Sélectionnez Largeur d'écran la plus petite, puis appuyez sur le bouton >>

enter image description here

Tapez 600 pour la plus petite largeur d'écran. Le nom du répertoire sera généré automatiquement. Dis OK.

enter image description here

Cliquez ensuite avec le bouton droit sur le fichier values-sw600dp nouvellement créé. Choisissez Nouveau> Fichier de ressources Values ​​. Tapez bools pour le nom.

valeurs-grandes

L'ajout d'un répertoire values-large n'est nécessaire que si vous prenez en charge la version antérieure à Android 3.2 (API de niveau 13). Sinon, vous pouvez ignorer cette étape. Le répertoire values-large correspond à values-sw600dp. (values-xlarge correspond à values-sw720dp.)

Pour créer le répertoire values-large, suivez les mêmes étapes que ci-dessus, mais dans ce cas, choisissez Taille plutôt que Largeur d'écran la plus petite. Sélectionnez Large. Le nom du répertoire sera généré automatiquement. 

enter image description here

Cliquez avec le bouton droit sur le répertoire comme précédemment pour créer le fichier bools.xml

7
Suragch

Après réponse de Ginny , je pense que le moyen le plus fiable de le faire est le suivant:

Comme décrit ici , mettez un booléen dans les ressources sw600dp. Il doit avoir le préfixe sw sinon cela ne fonctionnera pas correctement:

dans res/values-sw600dp/dimens.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isTablet">true</bool>
</resources>

dans res/values ​​/ dimens.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isTablet">false</bool>
</resources>

Créez ensuite une méthode pour récupérer ce booléen:

public class ViewUtils {
    public static boolean isTablet(Context context){
        return context.getResources().getBoolean(R.bool.isTablet);
    }
}

Et une activité de base à étendre des activités pour lesquelles vous souhaitez ce comportement:

public abstract class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (!ViewUtils.isTablet(this)) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
    }
}

Ainsi, chaque activité étendrait BaseActivity:

public class LoginActivity extends BaseActivity //....

Important: même si vous prolongez de BaseActivity, vous devez ajouter la ligne Android:configChanges="orientation|screenSize" à chaque Activity de votre fichier AndroidManifest.xml:

    <activity
        Android:name=".login.LoginActivity"
        Android:configChanges="orientation|screenSize">
    </activity>
6
RominaV

C'est un peu tard mais voici une solution XML-Only, mais une solution de piratage qui ne recrée pas une activité comme le fait setRequestedOrientation si doit changer d'orientation:

https://stackoverflow.com/a/27015879/1281930

4
guness

D'autres solutions n'ont pas fonctionné pour moi. Il me restait encore un problème d’orientation étrange avec les problèmes de dialogues et de loisirs. Ma solution a été d'étendre l'activité en la forçant comme portrait dans le manifeste.

Exemple:

public class MainActivityPhone extends MainActivity {}

manifest.xml:

        <activity
        Android:screenOrientation="portrait"
        Android:name=".MainActivityPhone"
        Android:theme="@style/AppTheme.NoActionBar" />

dans l'activité splashcreen:

    Intent i = null;
    boolean isTablet = getResources().getBoolean(R.bool.is_tablet);
    if (!isTablet)
        i = new Intent(this, MainActivityPhone.class);
    else
        i = new Intent(this, MainActivity.class);
    startActivity(i);
0
mengoni

Vieille question que je connais. Pour que votre application fonctionne toujours en mode portrait même lorsque l'orientation peut être ou est intervertie, etc. (par exemple sur des tablettes), j'ai conçu cette fonction qui permet de définir le périphérique dans la bonne orientation sans avoir besoin de savoir les fonctionnalités sont organisées sur l'appareil.

   private void initActivityScreenOrientPortrait()
    {
        // Avoid screen rotations (use the manifests Android:screenOrientation setting)
        // Set this to nosensor or potrait

        // Set window fullscreen
        this.activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        DisplayMetrics metrics = new DisplayMetrics();
        this.activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);

         // Test if it is VISUAL in portrait mode by simply checking it's size
        boolean bIsVisualPortrait = ( metrics.heightPixels >= metrics.widthPixels ); 

        if( !bIsVisualPortrait )
        { 
            // Swap the orientation to match the VISUAL portrait mode
            if( this.activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT )
             { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); }
            else { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ); }
        }
        else { this.activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); }

    }

Fonctionne comme un charme! 

AVIS: Modifiez this.activity par votre activité ou ajoutez-le à l'activité principale et supprimez this.activity ;-)

Si vous voulez faire le contraire, vous devez changer le code en paysage (mais je pense qu'il est clair comment procéder).

0
Codebeat

Malheureusement, l’utilisation de la méthode setRequestedOrientation (...) provoquera le redémarrage de l’activité. Ainsi, même si vous appelez cela dans la méthode onCreate, le cycle de vie de l’activité en sera répété, puis la même activité sera recréée orientation. Donc, dans la réponse de @Brian Christensen, vous devez considérer que le code d'activité peut être appelé deux fois, ce qui peut avoir des effets négatifs (non seulement visuels, mais également lors de requêtes réseau, d'analyses, etc.).

De plus, définir l'attribut configChanges dans le manifeste est, à mon avis, un gros compromis qui pourrait impliquer des coûts de refactorisation énormes. Les développeurs Android ne recommandent pas de modifier cet attribut .

Enfin, essayer de définir screenOrientation d'une manière ou d'une autre (pour éviter le problème de redémarrage) est impossible, statiquement impossible en raison du manifeste statique qui ne peut pas être modifié. Par programme, il est uniquement possible d'appeler cette méthode dans l'activité déjà démarrée. 

Résumé: À mon avis, la suggestion de @Brian Christensen est le meilleur compromis, mais soyez conscient du problème de la reprise d'activité.

0
mathew11