【问题标题】:How can I detect which layout is selected by Android in my application?如何检测 Android 在我的应用程序中选择了哪个布局?
【发布时间】:2013-11-24 21:52:43
【问题描述】:

假设我在不同的资源文件夹中有一个具有三种不同布局的活动。例如:

layout-land/my_act.xml
layout-xlarge/my_act.xml
layout-xlarge-land/my_act.xml

在不同的设备和不同的位置,其中一个是由 Android 选择的。
我如何才能找出哪一个被选择以编程方式

Android 是否有任何 API 可以将这些布局返回给程序?


编辑Graham Borland's solution在我在cmets中提到的某些情况下有问题。

【问题讨论】:

  • 在您的设备中?还是 XML 布局?
  • 我想知道在我的应用程序中以编程方式选择了哪个布局。
  • 不要介意我问你为什么想以编程方式了解这一点?
  • 好问题.. 这可以用于调查和理解 android 布局选择..
  • 我很失望你一再忽略更多信息的请求,这将有助于我诊断出你在我的回答中发现的问题。

标签: android android-layout resources


【解决方案1】:

您可以在每个不同资源文件中的视图上设置不同的android:tag 属性,并在运行时使用View.getTag() 读回标签。

例子:

layout-xlarge-land/my_act.xml

<View
    android:id="@+id/mainview"
    android:tag="xlarge-landscape"
/>

layout-xlarge/my_act.xml

<View
    android:id="@+id/mainview"
    android:tag="xlarge-portrait"
/>

MyActivity.java

String tag = view.getTag();
if (tag.equals("xlarge-landscape") {
    ...
}

【讨论】:

  • 现在我有 2 个布局。 1)layout2)layout-xlarge-land。第一个标签是“layout”,第二个标签是“layout-xlarge-land”。当我在onCreate() 方法中获得标签时,它给了我标签的真正价值,如“layout-xlarge-land”。 但是当我单击该页面中的按钮并在该按钮中使用findViewById() 并获取其标签时,其值为默认布局标签“布局”。为什么??????
  • 我在那个 Activity 中有一个 tabHost。我注意到在tabHost.addTab(myTabSpec); 行中,标签从“layout-xlarge-land”更改为“layout”?为什么???
  • 要回答您的第一个问题,请发布您的活动的 onCreate() 和您的按钮点击处理代码,以及布局文件的相关部分。
  • @breceivemail 我想帮助解决您在使用此方法时遇到的问题,但您需要提供更多信息。请发布您的活动的 onCreate() 和您的按钮点击处理代码,以及布局文件的相关部分。
  • @breceivemail 我相信TabHost 也使用该标签,因此您的使用可能会与它发生冲突。见grepcode.com/file/repository.grepcode.com/java/ext/…
【解决方案2】:

您可以为每个受支持的配置创建一个values-&lt;config&gt; 目录。在每个目录中,创建一个strings.xml,其中包含一个描述当前配置的selected_configuration 字符串。在运行时,使用标准的getString 方法获取字符串,该方法将为您进行配置解析并为配置返回正确的字符串。这是未经测试的。

【讨论】:

  • 很好的解决方案!!!我测试了它并且它有效。它没有在@Graham Borlans 的解决方案中发现的问题。
  • 为避免复制每个 values-&lt;config&gt; 资源文件夹的所有 strings.xml 内容,您可以创建一个自定义文件,如 layout_type.xml 并仅将 selected_configuration 放入其中。
  • 请问您在实施此@breceivemail 时是否体验过this issue
  • 太棒了!很好的解决方案。我在我的 values-large-land 目录上创建了一个 strings.xml,只在其上添加了一个名为 screen 的字符串资源并解决了问题。需要时从主 strings.xml 中获取所有其他字符串。完美
  • 简单就是卓越!谢谢!
【解决方案3】:

您可以尝试重复此算法"How Android Finds the Best-matching Resource" - 它非常简单,特别是如果您仅针对不同的屏幕使用不同的布局。

【讨论】:

  • 我已经尝试在android源中找到它,但它是本机代码。
  • 我觉得比较靠谱。你能给我们示例代码作为stackoverflow中的参考吗? :)
  • 选择顺序在这里developer.android.com/guide/topics/resources/…我想所有这些修改器都可以在Context.getResources().getConfiguration()找到
  • 我更喜欢这种方法作为答案。但它需要一个完整且适用的算法进行测试。因为@Graham 的回答乍一看似乎不错,但在我的一些复杂活动中遇到了问题。
  • 抱歉,我现在没时间做测试。如果我这样做,我会在这里写结果
【解决方案4】:

我的答案是从@Graham Borland 实现的

 @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        switch(metrics.densityDpi){
             case DisplayMetrics.DENSITY_LOW:

             if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
             {
               Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
               String tag = view.getTag();
               if (tag.equals("small-landscape") {
                .....
              }
             } 
            else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) 
            {
            Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
             String tag = view.getTag();
               if (tag.equals("small-potrait") {
                .....
              }
            }
            break;

             case DisplayMetrics.DENSITY_MEDIUM:

             if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
             {
               Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
               String tag = view.getTag();
               if (tag.equals("medium-landscape") {
                .....
              }
             } 
            else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) 
            {
            Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
             String tag = view.getTag();
               if (tag.equals("medium-potrait") {
                .....
              }
            }
             break;

             case DisplayMetrics.DENSITY_HIGH:

               if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
             {
               Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
               String tag = view.getTag();
               if (tag.equals("large-landscape") {
                .....
              }
             } 
            else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) 
            {
            Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
             String tag = view.getTag();
               if (tag.equals("large-potrait") {
                .....
              }
            }
             break;
        }

这适用于 API lavel 4 或更高版本。

【讨论】:

  • 现在我有 2 个布局。 1)layout2)layout-xlarge-land。第一个标签是“layout”,第二个标签是“layout-xlarge-land”。当我在onCreate() 方法中获得标签时,它给了我标签的真正价值,如“layout-xlarge-land”。 但是当我单击该页面中的按钮并在该按钮中使用findViewById() 并获取其标签时,其值为默认布局标签“布局”。为什么??????
  • 我在那个 Activity 中有一个 tabHost。我注意到在tabHost.addTab(myTabSpec); 行中,标签从“layout-xlarge-land”更改为“layout”?为什么???
【解决方案5】:

我假设您使用setContentView(int resID) 来设置您的活动内容。


方法1 (这是我的答案)

现在在你的所有布局中确保根视图总是有正确的标签:

示例:

layout-xlarge/main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:tag="xlarge-landscape"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

</LinearLayout>

layout-small/main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:tag="small"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

</LinearLayout>

现在让你的活动扩展这个活动:

package shush.android.screendetection;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class SkeletonActivity extends Activity {

    protected String resourceType;

    @Override
    public void setContentView(int layoutResID) {
        LayoutInflater inflater = getLayoutInflater();
        View view = inflater.inflate(layoutResID, null);
        resourceType = (String)view.getTag();
        super.setContentView(view);
    }
}

在这种情况下,您可以使用resourceType 来了解所使用的资源标识符。


方法 2 (这是我的答案,但在发布之前我想到了更好的答案)

现在在你的所有布局中确保根视图总是有正确的标签:

示例:

layout-xlarge/main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:tag="xlarge-landscape"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

</LinearLayout>

layout-small/main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:tag="small"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

</LinearLayout>

现在让你的活动扩展这个活动:

package shush.android.screendetection;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class SkeletonActivity extends Activity {

    @Override
    public void setContentView(int layoutResID) {
        LayoutInflater inflater = getLayoutInflater();
        View view = inflater.inflate(layoutResID, null);
        fix(view, view.getTag());
        super.setContentView(view);
    }

    private void fix(View child, Object tag) {
        if (child == null)
            return;

        if (child instanceof ViewGroup) {
            fix((ViewGroup) child, tag);
        }
        else if (child != null) {
            child.setTag(tag);
        }
    }

    private void fix(ViewGroup parent, Object tag) {
        for (int i = 0; i < parent.getChildCount(); i++) {
            View child = parent.getChildAt(i);
            if (child instanceof ViewGroup) {
                fix((ViewGroup) child, tag);
            } else {
                fix(child, tag);
            }
        }
    }
}

在这种情况下,层次结构中的所有视图都将具有相同的标签。

【讨论】:

  • 您的解决方案有问题。当您的屏幕旋转并且您的布局更改为纵向或横向时,您会怎么做?
  • 例如,如果您当前的标签是“xlarge-land”,则轮换标签必须更改为“xlarge-port”
  • 是吗?它会改变(将再次调用 onCreate 并设置标签)\
  • 你读过我对@Graham 回答的评论吗?我认为这些解决方案可能存在我在 cmets 中提到的问题。
  • 我给你 2 个有效的解决方案。您的评论状态表明布局是正常的,并且该方法没有任何问题。试试它们,如果它们不起作用,我很乐意提供帮助(:
【解决方案6】:

您可以从Resources 对象获取有关屏幕方向和大小的信息。从那里您可以了解使用了哪种布局。

getResources().getConfiguration().orientation; - 返回Configuration.ORIENTATION_PORTRAITConfiguration.ORIENTATION_LANDSCAPE

int size = getResources().getConfiguration().screenLayout; - 返回屏幕大小的掩码。您可以针对 Small、Normal、Large、xLarge 尺寸进行测试。例如:

if ((size & Configuration.SCREENLAYOUT_SIZE_XLARGE)==Configuration.SCREENLAYOUT_SIZE_XLARGE)

【讨论】:

    【解决方案7】:

    我不知道找到它的确切方法。但我们可以通过不同的方式找到它。

    在所有布局中添加一个文本视图。(隐藏可见性)。相应地分配 xlarge、land、xlarge-land 等值。

    在程序中,从 textview 中获取值。不知怎的,我们可以这样认识。

    【讨论】:

    • 看看@Graham Borland 的回答。这是你的解决方案。看看cmets。他的解决方案在某些情况下存在问题。
    【解决方案8】:

    您的问题与How to get layout xml file path? 相同
    您可以在 xml 中添加具有相应文件夹名称的隐藏文本视图 通过

    获取文本视图中的字符串
    TextView path = (TextView)findViewbyid(R.id.hiddentextview); 
     String s =  path.gettext().tostring();
    

    确保文本视图的所有 id 都相同。

    示例

    if your xml is in `normal-mdpi` in hidden textview hard code `normal-mdpi`
    if your xml is in `large-mdpi` in hidden textview hard code `large-mdpi`
    

    【讨论】:

    • 看看@Graham Borland 的回答。这是你的解决方案。看看cmets。他的解决方案在某些情况下存在问题。
    • 此方法没有错误余地,您将获得确切的值或字符串,如果您获得另一个字符串,则激活该布局。您在 10 英寸平板电脑中使用上述应用吗?要激活“layout-xlarge-land”,您应该在横向模式下使用 10 英寸平板电脑,试一试并发布您的结果。
    • 当你的Activity有标签时,字符串的值会发生变化。
    • 将找到解决方案并尽快发布
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多