Android: Hoch- und Querformat für Tablets zulassen, aber Hochformat auf dem Telefon erzwingen?

191

Ich möchte, dass Tablets im Hoch- und Querformat (sw600dp oder höher) angezeigt werden können, Telefone jedoch nur im Hochformat. Ich kann keine Möglichkeit finden, eine Orientierung bedingt zu wählen. Irgendwelche Vorschläge?

Kenny Wyland
quelle
Eine Möglichkeit wäre, KEINE Landschaftslayouts für Telefone zu entwerfen, wie dies bei der Verwendung layout-landinnerhalb des resOrdners der Fall ist .
Ghost
12
Dies würde nur dazu führen, dass das Hochformat im Querformat angezeigt wird. Es wird nicht verhindern, dass sich ein Telefon in die Landschaft dreht.
Radley

Antworten:

446

Hier ist eine gute Möglichkeit, Ressourcen und Größenqualifizierer zu verwenden .

Fügen Sie diese Bool-Ressource in res / values ​​als bools.xml oder was auch immer ein (Dateinamen spielen hier keine Rolle):

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

Fügen Sie dieses in res / values-sw600dp und res / values-xlarge ein:

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

In dieser ergänzenden Antwort finden Sie Hilfe zum Hinzufügen dieser Verzeichnisse und Dateien in Android Studio.

In der onCreate-Methode Ihrer Aktivitäten können Sie Folgendes tun:

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

Vorrichtungen , die mehr als 600 dp in der kleinsten Breitenrichtung sind, oder x-large auf vorge Android 3.2 Geräte (Tabletten, im Grunde) werden wie normale Verhalten, basierend auf Sensor und benutzer verriegelte Drehung, etc . Alles andere (Telefone, so ziemlich) wird nur im Hochformat sein.

Brian Christensen
quelle
1
Muss ich auch verwenden xlargeoder kann ich nur verwenden sw600dp? Es gibt heutzutage wahrscheinlich keine Tablets mit <3,2.
Theblang
7
Nun, dies startet möglicherweise die Aktivität neu, wenn sie in der Landschaft gestartet wird, siehe developer.android.com/reference/android/app/…
Bondax
1
@Bondax Dieser Kommentar gilt nur für "Wenn sich die Aktivität derzeit im Vordergrund befindet oder die Bildschirmausrichtung anderweitig beeinflusst". Dies kann nicht der Fall sein, da wir uns zu diesem Zeitpunkt in onCreate befinden.
Brian Christensen
1
@BrianChristensen Ich habe beobachtet, wie eine Aktivität neu gestartet wurde, als die gewünschte Ausrichtung eingestellt wurde onCreate(). Als ich den Anruf setRequestedOrientation()in Zeit und Kontext an eine andere Position verschoben habe , fand der Neustart nicht mehr statt.
Bondax
8
Wenn ich die App im Querformat starte, wird für einen kurzen Moment immer noch der Querformatmodus angezeigt.
白 目
29

Sie können auf diese Weise versuchen, zuerst die Bildschirmgröße des Geräts zu ermitteln

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

und dann die Ausrichtung entsprechend einstellen

setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Avi Kumar Manku
quelle
4
Welche Methode sollte ich die setRequestedOrientation () -Methode setzen? Sobald onCreate gestartet wurde, hat es bereits die gewünschte Ausrichtung ausgewählt.
Kenny Wyland
kenny check this Ich denke, es könnte dir helfen stackoverflow.com/questions/2833474/…
Avi Kumar Manku
Ich sehe, dass diese Antwort positiv bewertet wurde, bin mir aber nicht sicher, ob sie das Problem löst. Configurationliefert screenLayoutInformationen - DPI. Während sich die Frage auf die Bildschirmgröße des physischen Geräts bezieht - Telefon VS Tablet. Das heißt, Sie können ein Configuration.SCREENLAYOUT_SIZE_NORMALund es wäre ein MDPI-Tablet.
Nightfixed
Ich stehe
Aditya Vyas-Lakhan
10

Ergänzung zur akzeptierten Antwort

In Android Studio können Sie die folgenden Schritte ausführen, um die Verzeichnisse res/values-sw600dpund res/values-largemit ihren bools.xmlDateien hinzuzufügen .

Werte-sw600dp

Wählen Sie zunächst auf der Registerkarte Projekt im Navigator den Filter Projekt (anstelle von Android) aus.

Geben Sie hier die Bildbeschreibung ein

Klicken Sie dann mit der rechten Maustaste auf das app/src/main/resVerzeichnis. Wählen Sie " Neu" > " Android-Ressourcenverzeichnis" .

Wählen Sie Kleinste Bildschirmbreite und drücken Sie die Taste >> .

Geben Sie hier die Bildbeschreibung ein

Geben Sie 600für die kleinste Bildschirmbreite ein. Der Verzeichnisname wird automatisch generiert. Sag OK.

Geben Sie hier die Bildbeschreibung ein

Klicken Sie dann mit der rechten Maustaste auf die neu erstellte values-sw600dpDatei. Wählen Sie " Neu" > " Werte" . Geben Sie boolsden Namen ein.

Werte groß

Das Hinzufügen eines values-largeVerzeichnisses ist nur erforderlich, wenn Sie vor Android 3.2 (API-Stufe 13) unterstützen. Andernfalls können Sie diesen Schritt überspringen. Das values-largeVerzeichnis entspricht values-sw600dp. ((values-xlarge entspricht values-sw720dp.)

Führen Sie zum Erstellen des values-largeVerzeichnisses die gleichen Schritte wie oben aus. Wählen Sie in diesem Fall jedoch Größe anstelle der kleinsten Bildschirmbreite. Wählen Sie Groß . Der Verzeichnisname wird automatisch generiert.

Geben Sie hier die Bildbeschreibung ein

Klicken Sie wie zuvor mit der rechten Maustaste auf das Verzeichnis, um die bools.xmlDatei zu erstellen .

Suragch
quelle
2
Lassen Sie mich wissen, wenn dies nicht funktioniert und ich werde es beheben. Es hat bei mir funktioniert. Ich habe eine Ablehnung erhalten, aber keinen Kommentar, daher weiß ich nicht, was ich beheben soll.
Suragch
9

So habe ich es gemacht (inspiriert von http://androidblogger.blogspot.com/2011/08/orientation-for-both-phones-and-tablets.html ):

In AndroidManifest.xml müssen Sie für jede Aktivität, die Sie zwischen Hoch- und Querformat wechseln möchten (stellen Sie sicher, dass Sie screenSize hinzufügen - dies wurde früher nicht benötigt!). Hier müssen Sie keine Bildschirmausrichtung festlegen. ::

android:configChanges="keyboardHidden|orientation|screenSize"

Methoden zum Hinzufügen zu jeder Aktivität:

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

und: (Wenn Sie diese Methode nicht überschreiben, ruft die App beim Ändern der Ausrichtung onCreate () auf.)

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

In onCreate () jeder Aktivität:

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

Das einzige, was ich anscheinend nicht herausfinden kann, ist, wie ich die App dazu bringen kann, Layoutdateien zu ändern, wenn ich von Querformat zu Hochformat oder umgekehrt wechsle. Ich gehe davon aus, dass die Antwort etwas Ähnliches tut wie der obige Link, aber ich konnte das nicht für mich zum Laufen bringen - es hat alle meine Daten gelöscht. Wenn Sie jedoch eine App haben, die so einfach ist, dass Sie dieselbe Layoutdatei für Hoch- und Querformat haben, sollte dies funktionieren.

Ginny
quelle
2
Legen Sie
Sie erhalten eine Ausnahme, wenn Sie nicht super onConfigurationChanged
RominaV
8

Nach Ginnys Antwort denke ich, dass der zuverlässigste Weg dies ist:

Fügen Sie wie hier beschrieben einen Booleschen Wert in die Ressourcen sw600dp ein. Es muss das Präfix sw haben, sonst funktioniert es nicht richtig:

in res / values-sw600dp / dimension.xml

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

in res / values ​​/ dimension.xml

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

Erstellen Sie dann eine Methode, um diesen Booleschen Wert abzurufen:

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

Und eine Basisaktivität, die sich von den Aktivitäten erstreckt, bei denen Sie dieses Verhalten wünschen:

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

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

Jede Aktivität würde also BaseActivity erweitern:

public class LoginActivity extends BaseActivity //....

Wichtig : Auch wenn Sie von erweitern BaseActivity, müssen Sie die Zeile in Ihrer AndroidManifest.xml android:configChanges="orientation|screenSize"zu jeder Zeile Activityhinzufügen:

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

Nun, das ist etwas spät, aber hier ist eine reine XML- Lösung, aber eine Hack-Lösung, die keine Aktivität als neu erstelltsetRequestedOrientation ob sie die Ausrichtung ändern müsste:

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

Waffe
quelle
1
Funktioniert nicht, Tablets nehmen immer die Ausrichtung von Telefonen an. Anscheinend wird android: screenOrientation für alle Aktivitäten im Manifest genau einmal festgelegt, bevor Ressourcenmodifikatoren angewendet werden.
0101100101
2

Nach der akzeptierten Antwort füge ich die Kotlin-Datei mit der Lösung hinzu, die hoffentlich jemandem hilft

Fügen Sie diese Bool-Ressource res/valuesals bools.xml oder was auch immer ein (Dateinamen spielen hier keine Rolle):

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

Setzen Sie dieses ein res/values-sw600dpund res/values-sw600dp-land:

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

Fügen Sie es dann in Ihrer Aktivität oder Fragmentität in die folgenden Zeilen ein

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
quelle
1

Andere Lösungen haben bei mir nicht funktioniert. Ich hatte immer noch ein seltsames Orientierungsproblem mit Dialogen und Erholungsproblemen. Meine Lösung bestand darin, die Aktivität zu erweitern und sie als Porträt im Manifest zu erzwingen.

Beispiel:

public class MainActivityPhone extends MainActivity {}

manifest.xml:

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

in Splashcreen-Aktivität:

    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
quelle
0

Alte Frage, die ich kenne. Um Ihre App immer im Hochformat auszuführen, auch wenn die Ausrichtung geändert werden kann oder wird usw. (z. B. auf Tablets), habe ich diese Funktion entwickelt, mit der das Gerät in die richtige Ausrichtung gebracht wird, ohne dass Sie wissen müssen, wie das Hoch- und Querformat ist Funktionen sind auf dem Gerät organisiert.

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

    }

Klappt wunderbar!

HINWEIS: Ändern Sie this.activitydurch Ihre Aktivität oder fügen Sie es der Hauptaktivität hinzu und entfernen Sie this.activity;-)

Wenn Sie das Gegenteil tun möchten, müssen Sie den Code in Querformat ändern (aber ich denke, es ist klar, wie das geht).

Codebeat
quelle
0

Leider führt die Verwendung der Methode setRequestedOrientation (...) dazu, dass die Aktivität neu gestartet wird. Selbst wenn Sie dies in der onCreate-Methode aufrufen, durchläuft sie den Aktivitätslebenszyklus und erstellt dann dieselbe Aktivität in der angeforderten Ausrichtung neu. Bei der Antwort von @Brian Christensen sollten Sie berücksichtigen, dass der Aktivitätscode möglicherweise zweimal aufgerufen wird. Dies kann negative Auswirkungen haben (nicht nur visuell, sondern auch bei Netzwerkanforderungen, Analysen usw.).

Darüber hinaus ist das Festlegen des configChanges-Attributs im Manifest meiner Meinung nach ein großer Kompromiss, der massive Refactoring-Kosten verursachen könnte. Android-Entwickler empfehlen nicht, dieses Attribut zu ändern .

Schließlich ist der Versuch, die screenOrientation irgendwie anders einzustellen (um das Problem des Neustarts zu vermeiden) unmöglich, statisch unmöglich, da das statische Manifest nicht geändert werden kann. Programmatisch ist es nur möglich, diese Methode in der bereits gestarteten Aktivität aufzurufen.

Zusammenfassung: Meiner Meinung nach ist der Vorschlag von @Brian Christensen der beste Kompromiss, aber beachten Sie das Problem der Neustartaktivität.

mathew11
quelle