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

191

Je souhaite que les tablettes puissent s'afficher en mode portrait et paysage (sw600dp ou supérieur), mais les téléphones doivent être limités au portrait uniquement. Je ne trouve aucun moyen de choisir conditionnellement une orientation. Aucune suggestion?

Kenny Wyland
la source
Une façon serait de NE PAS concevoir de mises en page de paysage pour les téléphones, comme en utilisant un dossier layout-landinterne res.
Ghost
12
Cela ne ferait que montrer la mise en page du portrait en paysage. Cela n'empêchera pas réellement un téléphone de tourner en mode paysage.
radley

Réponses:

446

Voici un bon moyen d'utiliser les ressources et les qualificatifs de taille .

Mettez cette ressource booléenne dans res / values ​​sous forme de bools.xml ou autre (les noms de fichiers n'ont pas d'importance 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>

Consultez 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 qui sont plus de 600 dp dans le sens de la largeur la plus petite, ou x-large sur les dispositifs de pré-applications 3.2 (comprimés, essentiellement) se comportent comme d' habitude, la rotation sur la base de capteur et verrouillé par l' utilisateur, etc . Tout le reste (téléphones, à peu près) sera uniquement portrait.

Brian Christensen
la source
1
Dois-je utiliser xlargeaussi ou puis-je simplement utiliser sw600dp? Il n'y a probablement plus de tablettes fonctionnant sous 3,2 ces jours-ci.
theblang
7
Eh bien, cela redémarre potentiellement l'activité une fois lancée dans le paysage, voir developer.android.com/reference/android/app
...
1
@Bondax Ce commentaire s'applique uniquement "Si l'activité est actuellement au premier plan ou a un impact sur l'orientation de l'écran", ce qui ne peut pas être le cas puisque nous sommes dans onCreate à ce stade.
Brian Christensen
1
@BrianChristensen J'ai observé le redémarrage d'une activité lors de la définition de l'orientation demandée dans onCreate(). Lorsque j'ai déplacé l'appel à setRequestedOrientation()une position différente dans le temps et dans le contexte, le redémarrage n'a plus eu lieu.
Bondax
8
si je lance l'application en mode paysage, elle affiche toujours le mode paysage pendant un bref instant.
最 白 目
29

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éfinissez l'orientation en fonction de cela

setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Avi Kumar Manku
la source
4
Quelle méthode dois-je mettre la méthode setRequestedOrientation ()? Une fois que onCreate a démarré, il a déjà choisi l'orientation qu'il souhaite.
Kenny Wyland
kenny vérifier cela, je pense que cela pourrait vous aider stackoverflow.com/questions/2833474/…
Avi Kumar Manku
Je vois que cette réponse a été votée pour, mais je ne suis pas sûr qu'elle résout le problème. Configurationfournit des screenLayoutinformations - DPI. Alors que la question est liée à la taille de l'écran de l'appareil physique - téléphone VS tablette. Configuration.SCREENLAYOUT_SIZE_NORMALCela signifie que vous pouvez avoir un et ce serait une tablette MDPI.
nuit fixée
Je suis confronté à un problème stackoverflow.com/questions/42172864/…
Aditya Vyas-Lakhan
10

Complément à la réponse acceptée

Vous pouvez effectuer les étapes suivantes dans Android Studio pour ajouter les répertoires res/values-sw600dpet res/values-largeavec leurs bools.xmlfichiers.

valeurs-sw600dp

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

entrez la description de l'image ici

Cliquez ensuite avec le bouton droit sur le app/src/main/resrépertoire. Choisissez Nouveau > Répertoire de ressources Android .

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

entrez la description de l'image ici

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

entrez la description de l'image ici

Cliquez ensuite avec le bouton droit sur le values-sw600dpfichier nouvellement créé . Choisissez Nouveau > Fichier de ressources de valeurs . Saisissez boolsle nom.

valeurs-grandes

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

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

entrez la description de l'image ici

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

Suragch
la source
2
Faites-moi savoir si cela ne fonctionne pas et je vais le réparer. Cela a fonctionné pour moi. J'ai eu un vote négatif mais aucun commentaire, donc je ne sais pas quoi corriger.
Suragch
9

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é, 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 une orientation de l'écran ici. :

android:configChanges="keyboardHidden|orientation|screenSize"

Méthodes à ajouter dans 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'orientation)

@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 pour que l'application change les fichiers de mise en page lors du passage du paysage au portrait ou vice versa. Je suppose que la réponse fait quelque chose de similaire à ce que fait le lien ci-dessus, mais je n'ai pas pu faire fonctionner cela pour moi - cela a supprimé toutes mes données. Mais si vous avez une application assez simple pour avoir le même fichier de mise en page pour le portrait et le paysage, cela devrait fonctionner.

Ginny
la source
2
mettre des mises en page de paysage dans votre dossier layout-land
radley
Vous obtiendrez une exception si vous n'appelez pas super onConfigurationChanged
RominaV
8

Suite à la 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 resources 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>

Ensuite, créez 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 à partir 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 étendez de BaseActivity, vous devez ajouter la ligne android:configChanges="orientation|screenSize"à chacun Activitydans votre AndroidManifest.xml:

    <activity
        android:name=".login.LoginActivity"
        android:configChanges="orientation|screenSize">
    </activity>
RominaV
la source
5

Eh bien, c'est un peu tard mais, voici une solution XML-Only mais une solution de hack qui ne recrée pas une activité comme setRequestedOrientationsi elle doit changer d'orientation:

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

guness
la source
1
Ne fonctionne pas, les tablettes prennent toujours l'orientation des téléphones. Apparemment, le paramètre android: screenOrientation est défini exactement une fois pour toutes les activités du manifeste, avant que les modificateurs de ressources ne soient appliqués.
0101100101
2

Suite à la réponse acceptée , j'ajoute le fichier kotlin avec la solution en espérant que cela aide quelqu'un

Mettez cette ressource booléenne en res/valuestant que bools.xml ou autre (les noms de fichiers n'ont pas d'importance ici):

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

Mettez celui-ci res/values-sw600dpet res/values-sw600dp-land:

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

Ensuite, ajoutez-le dans les lignes ci-dessous dans votre activité ou fragmentvity

class MyActivity : Activity() {

    @SuppressLint("SourceLockedOrientationActivity")
    override fun onCreate(savedInstanceState: Bundle?) {
        if (resources.getBoolean(R.bool.portrait_only)) {
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        }
        super.onCreate(savedInstanceState)
    }

    @SuppressLint("SourceLockedOrientationActivity")
    override fun onConfigurationChanged(newConfig: Configuration) {
        if (resources.getBoolean(R.bool.portrait_only)) {
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        }
        super.onConfigurationChanged(newConfig)
    }
}
Rahul
la source
1

Les autres solutions n'ont pas fonctionné pour moi. J'avais encore un problème d'orientation étrange avec les dialogues et les problèmes de loisirs. Ma solution était 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é de l'écran de démarrage:

    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);
mengoni
la source
0

Vieille question que je connais. Afin d'exécuter votre application toujours en mode portrait, même lorsque l'orientation peut être ou est permutée, etc. (par exemple sur les tablettes), j'ai conçu cette fonction qui est utilisée pour régler l'appareil dans la bonne orientation sans avoir besoin de savoir comment le portrait et le paysage 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.activityvotre activité ou ajoutez-la à l'activité principale et supprimez-la this.activity;-)

Si vous voulez faire le contraire, vous devez changer le code en paysage (mais je pense que la façon de procéder est claire).

Codebeat
la source
0

Malheureusement, l'utilisation de la méthode setRequestedOrientation (...) entraînera le redémarrage de l'activité, donc même si vous l'appelez dans la méthode onCreate, elle passera par le cycle de vie de l'activité, puis recréera la même activité dans l'orientation demandée. Donc, à la réponse de @Brian Christensen, vous devez considérer que le code d'activité peut être appelé deux fois, cela pourrait avoir des effets néfastes (non seulement visuels, mais aussi aux demandes du réseau, aux analyses, etc.).

De plus, définir l'attribut configChanges dans le manifeste est à mon avis un gros compromis, qui pourrait entraîner un coût de refactoring massif. 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 différente (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 n'est possible d'appeler cette méthode que 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 redémarrage de l'activité.

mathew11
la source