web-dev-qa-db-ja.com

Android:タブレットでポートレートとランドスケープを許可しますが、電話でポートレートを強制しますか?

タブレットを縦向きと横向き(sw600dp以上)で表示できるようにしたいのですが、電話は縦向きのみに制限されます。オリエンテーションを条件付きで選択する方法が見つかりません。助言がありますか?

179
Kenny Wyland

resources および size qualifiers を使用する良い方法があります。

このboolリソースを、bools.xmlまたは何でもres/valuesに入れます(ファイル名はここでは関係ありません):

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

これをres/values-sw600dpおよびres/values-xlargeに入れます。

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

これらのディレクトリとファイルをAndroid St​​udioに追加する方法については、 この補足回答 をご覧ください。

次に、アクティビティのonCreateメソッドでこれを実行できます。

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

最小幅方向で600 dpを超えるデバイス、またはAndroid 3.2より前のデバイス(基本的にはタブレット)でxラージのデバイスは、通常のように動作します センサーおよびユーザーロック回転などに基づいて 。他のすべて(電話、ほとんど)はポートレートのみになります。

430

この方法を試して、最初にデバイスの画面サイズを取得できます

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

そして、それに応じて方向を設定します

setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
28
Avi Kumar Manku

ここに私がそれをした方法があります( http://androidblogger.blogspot.com/2011/08/orientation-for-both-phones-and-tablets.html に触発されました):

AndroidManifest.xmlで、ポートレートとランドスケープの間で変更できるようにするアクティビティごとに(screenSizeを追加してください-これは必要ありませんでした!)ここで画面の向きを設定する必要はありません。 :

Android:configChanges="keyboardHidden|orientation|screenSize"

各アクティビティに追加するメソッド:

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

および:(このメソッドをオーバーライドしない場合、アプリは向きを変更するときにonCreate()を呼び出します)

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

各アクティビティのonCreate()で:

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

私が理解できないと思われる唯一のことは、横から縦に、またはその逆に切り替えるときに、アプリでレイアウトファイルを変更する方法です。私は答えが上記のリンクと同じようなことをしていると思いますが、私のためにそれを機能させることができませんでした-それはすべてのデータを削除しました。ただし、ポートレートとランドスケープで同じレイアウトファイルを使用できるほどシンプルなアプリがある場合は、これで機能するはずです。

9
Ginny

受け入れられた回答 の補足

Android St​​udioで次の手順を実行して、res/values-sw600dpおよびres/values-largeディレクトリとそれらのbools.xmlファイルを追加できます。

値-sw600dp

まず、[プロジェクト]タブから、ナビゲーターの[プロジェクト(Androidではなく)]フィルターを選択します。

enter image description here

次に、app/src/main/resディレクトリを右クリックします。 New>Android Resource Directoryを選択します。

Smallest Widthを選択し、>>ボタンを押します。

enter image description here

最小画面幅の600を入力します。ディレクトリ名は自動的に生成されます。 OKと言ってください。

enter image description here

次に、新しく作成されたvalues-sw600dpファイルを右クリックします。 New>Valuesリソースファイルを選択します。名前にboolsと入力します。

値が大きい

values-largeディレクトリの追加は、Android 3.2以前(APIレベル13)をサポートしている場合にのみ必要です。それ以外の場合は、この手順をスキップできます。 values-largeディレクトリはvalues-sw600dpに対応しています。 (values-xlargevalues-sw720dpに対応します。)

values-largeディレクトリを作成するには、上記と同じ手順に従いますが、この場合、最小画面幅ではなくSizeを選択します。 Largeを選択します。ディレクトリ名は自動的に生成されます。

enter image description here

前と同じようにディレクトリを右クリックして、bools.xmlファイルを作成します。

7
Suragch

Ginny's answer に従って、最も信頼できる方法は次のとおりだと思います。

here で説明したように、リソースsw600dpにブール値を入れます。プレフィックスswが必要です。そうでない場合、正しく動作しません。

res/values-sw600dp/dimens.xml内

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

res/values/dimens.xml内

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

次に、そのブール値を取得するメソッドを作成します。

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

そして、この動作が必要なアクティビティから拡張する基本アクティビティ:

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

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

したがって、各アクティビティはBaseActivityを拡張します。

public class LoginActivity extends BaseActivity //....

重要BaseActivityから拡張する場合でも、_Android:configChanges="orientation|screenSize"行を各Activityに追加する必要がありますAndroidManifest.xml:

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

さて、これは少し遅いですが、ここではXML-Onlyですが、アクティビティをsetRequestedOrientationとして再作成しないハックソリューションです向きを変更する必要がある場合:

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

4
guness

他のソリューションは私にとってはうまくいきませんでした。私はまだダイアログとレクリエーションの問題で奇妙なオリエンテーションの問題を抱えていました。私の解決策は、アクティビティを拡張して、マニフェストのポートレートとして強制することでした。

例:

public class MainActivityPhone extends MainActivity {}

manifest.xml:

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

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

私が知っている古い質問。 (タブレットなど)向きが入れ替わる場合でもアプリを常にポートレートモードで実行するために、ポートレートとランドスケープの方法を知らなくてもデバイスを正しい向きに設定するために使用されるこの機能を設計しました機能はデバイス上で整理されています。

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

    }

チャームのように機能します!

注意:アクティビティによってthis.activityを変更するか、メインアクティビティに追加してthis.activityを削除してください;-)

反対のことをしたい場合は、コードをランドスケープに変更する必要があります(ただし、これを行う方法は明確だと思います)。

0
Codebeat

残念ながら、メソッド setRequestedOrientation(...) を使用するとアクティビティが再起動されるため、onCreateメソッドでこれを呼び出してもアクティビティライフサイクルを経てから同じアクティビティが再作成されます要求された向きで。したがって、@ Brian Christensenの回答では、アクティビティコードが2回呼び出される可能性があることを考慮する必要があります(視覚的だけでなく、ネットワークリクエスト、分析などでも)悪影響が生じる可能性があります。

さらに、マニフェストでconfigChanges属性を設定することは、私の意見では大きなトレードオフであり、大きなリファクタリングコストがかかる可能性があります。 Androidデベロッパーはその属性を変更することを推奨していません

最後に、screenOrientationを何らかの方法で(再起動の問題を回避するために)設定しようとすることは不可能です。変更できない静的マニフェストのために静的に不可能です。

要約:私の意見では、@ Brian Christensenの提案は最良のトレードオフですが、アクティビティの再開の問題に注意してください。

0
mathew11