1

私はどこでも検索しましたが、これを行う方法をまったく見つけることができません:

私のプロジェクトでは、レイアウト用に2つのリソースフォルダーがあります。1つは「layout」と呼ばれ、もう1つは「layout-land」と呼ばれます。これは、現在の向きに応じて使用されるアクティビティごとに2つの別々のレイアウトを持つおなじみの方法です。問題は、アクティビティごとに個別の「レイアウトランド」レイアウトがないことです。また、すべてのアクティビティがランドスケープモードに異なるレイアウトを必要とするわけではありません。

私が行ったことはonConfigurationChanged、向きの変更が発生しないようにデフォルトをオーバーライドします(configChanges="orientation"マニフェストに適切なものを使用)。これにより、ユーザーが画面を傾けるたびにバンドルに詰め込むという頭痛の種をたくさん減らすことができました。ただし、実際に向きを変えたい場合もあります。「layout-land」フォルダに対応するレイアウトがあるときはいつでも、通常どおりに向きを変更したいと思います。onConfigurationChangedないときはいつでも、向き変更イベントを抑制し たい。

私は、すべてのアクティビティの基本クラスでBaseActivityある拡張クラスを作成し、オーバーライドしました。ActivityonConfigurationChanged

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

    if(...there is a layout-land version of the current activity's layout...)
    {
        setRequestedOrientation(newConfig.orientation);
    }
    else
    {
        // Do nothing, since raising the orientation change event
        // to change from a portrait layout to the same portrait layout is silly.
    }
}

唯一の問題は、レイアウトリソースのレイアウトランドバージョンがあるかどうかを判断する方法が見つからないことです。現在のレイアウトのリソースID(BaseActivityオーバーライドによってクラスの他の場所で取得)はすでにわかっていますが、レイアウトの横向きバージョンと縦向きバージョンの両方が同じIDを共有しており、オブジェクトがどちらをsetContentView簡単に教えてくれるかわかりません。 ResourcesIDで特定のリソースを要求したときに表示されるレイアウトのバージョン。これを行う方法が必要です。私は何が欠けていますか?

4

2 に答える 2

1

layout_land フォルダーのレイアウトで、最も外側の FrameLayout に id = layout_name_of_this_file を追加します。例えば

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout_name_of_this_file"
    .....

そしてあなたのコードで

getResources().getIdentifier("layout_name_of_this_file", "id", "com.example....")) = resource id of the button (a pretty long number)

getResources().getIdentifier("layout_name_of_the_layout_file_exist_in_layout_but_not_in_layout_land", "id", "com.example....")) = 0  

この ID を持つ FrameLayout がないためです。

于 2013-03-06T23:41:59.217 に答える
1

さて、私は解決策を見つけましたが、惨めでハッキングされた解決策でした。このハックはお勧めしません。悪魔でできているからです。

アクティビティのメソッドResourcesから取得できるオブジェクトだけgetResources()では、リソースの「レイアウトランド」バージョンがあるかどうかはわかりません。ただし、オブジェクトのメソッドを呼び出すことによって、オブジェクトが内部的に使用するAssetManagerオブジェクトを取得できます。ResourcesgetAssets()

AssetManagerオブジェクトには と呼ばれるメソッドがあり、フォルダ内openNonAssetFdの特定のファイルのファイル記述子を取得しようとしresます。残念ながら、このメソッドで開こうとするもののほとんど (すべてではないにしても) はFileNotFoundException、ファイルが存在する場合でも をスローします!

たとえば、 というファイルがある場合、「このファイルはファイル記述子として開くことができません。圧縮されている可能性があります」というメッセージとともにres/layout-land/settings_menu.xmlがスローされます。FileNotFoundException技術的には、ファイルはそこにあり、スローされる例外は少なくとも別のタイプである必要があるため、これは Android 関係者の設計が不適切です。

ただし、さらに重要なことは、レイアウトの単なる存在を検出する目的で、layout-landスローされた例外の戻りメッセージの違いに依存できることです。ここにハックがあります:

ファイルが存在する場合、「このファイルはファイル記述子として開くことができません。圧縮されている可能性があります」という例外メッセージが表示されます。

ファイルが存在しない場合、例外メッセージはopenNonAssetFdメソッドに渡したパラメーターと同じになります (つまり、存在しないリソースのファイル名になります)。

これで、次のようなメソッドを作成できます。

protected boolean landscapeLayoutExists(int layoutId)
{
// Since we're always passing in an id of a layout, this will always correspond
// to a layout file in any of the layout folders (either layout, or both layout and layout-land, in my case).
String rawName = this.getResources().getResourceEntryName(layoutId);
String testPath = "res/layout-land/" + rawName + ".xml";

try
{
    this.getResources().getAssets().openNonAssetFd(testPath);
}
catch(Exception ex)
{
    if(ex.getMessage().equals(testPath))
        return false;
    else
        return true;
}   

// Somehow, we managed to grab the file descriptor successfully.  
// In my experience, this cannot happen with layouts, but if it ever does,
// then we definitely know the file exists.
return true;
}

このメソッドを使用することで、現在のアクティビティのレイアウトのバージョンが "layout-land" フォルダーにあるかどうかを判断し、それに応じて行動できるようになりました。

ただし、このアプローチには満足していませんが、機能します (現時点では、少なくともこれをテストした Galaxy S3 では)。誰かがより良いものを持っているなら、私に知らせてください。

于 2013-03-06T23:23:34.647 に答える