1

我到处搜索,根本找不到任何方法:

在我的项目中,我有两个用于布局的资源文件夹:一个称为“layout”,另一个称为“layout-land”。这是根据当前方向为每个 Activity 使用两个独立布局的熟悉方式。问题是我没有为每个 Activity 单独的“layout-land”布局,而且并不是所有的 Activity 甚至都需要不同的横向模式布局。

我所做的是覆盖默认值onConfigurationChanged以防止发生方向更改(configChanges="orientation"在清单中使用适当的)。每次用户倾斜屏幕时,这让我省去了很多将东西塞进 Bundle 中的麻烦。但是,在某些情况下,我实际上希望发生方向变化。每当“layout-land”文件夹中有相应的布局时,我希望方向像往常一样改变。每当没有时,我想onConfigurationChanged抑制方向更改事件。

我创建了一个父BaseActivity类,它扩展Activity并且是我所有活动的基类,并覆盖onConfigurationChanged

@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通过覆盖在我的班级的其他地方获得setContentView),但是布局的横向版本和纵向版本共享相同的 id,我看不到Resources对象告诉我哪个简单的方法当我通过 id 向它询问特定资源时它给我的布局版本。必须有办法做到这一点。我错过了什么?

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您可以从 Activity 的方法中获取的对象getResources()本身不会告诉您是否存在资源的“布局-土地”版本。但是,您可以通过调用其方法来获取AssetManager对象内部使用的对象。ResourcesgetAssets()

AssetManager对象有一个名为 的方法openNonAssetFd,它将尝试获取文件夹中特定文件的文件描述符resFileNotFoundException不幸的是,即使文件存在,您尝试使用此方法打开的大多数(如果不是全部)内容都会抛出!

因此,例如,如果您有一个名为 的文件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 回答