如何检测我的应用程序中Android选择的布局?


69

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

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

Android在不同的设备和不同的位置中选择了其中之一。
如何找到以编程方式选择的一个?

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


编辑Graham Borland的解决方案在我在评论中提到的某些情况下存在问题。


在您的设备上?或XML布局?
Praveenkumar 2012年

我想知道以编程方式在我的应用程序中选择了哪种布局。
鲍勃2012年

不要介意我问你为什么要以编程方式知道这一点?
MrJre 2012年

2
好问题..这可以用于调查和理解android布局选择..
罗尼2012年

1
我很失望您一再忽略要求提供更多信息的要求,这将有助于我诊断您在回答中发现的问题。
Graham Borland

Answers:


44

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


很好的解决方案!!!我测试了它,而且效果很好。它没有@Graham Borlans解决方案中发现的问题。
鲍勃2012年

1
为了避免复制strings.xml每个values-<config>资源文件夹的所有内容,可以创建一个自定义文件,例如layout_type.xml,然后仅将selected_configuration其放入其中。
鲍勃2012年

请问您在实施此@breceivemail时是否遇到此问题
BrantApps 2012年

惊人!很好的解决方案。我在values-large-land目录中创建了strings.xml,仅在其上添加了一个名为screen的字符串资源,并解决了该问题。需要时,其他所有字符串都可以从main strings.xml中获取。完美
Herrera

简单就是卓越!谢谢!
塔什·佩姆希瓦

72

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

例:

布局-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()并获取其标签时,其值为默认布局标签“ layout”。为什么?????
鲍勃2012年

我在该活动中有一个tabHost。我注意到,tabHost.addTab(myTabSpec);代码行从“ layout-xlarge-land”更改为“ layout”?为什么???
鲍勃2012年

要回答第一个问题,请发布活动的onCreate()和按钮单击处理代码以及布局文件的相关部分。
格雷厄姆·博兰

@breceivemail我想帮助您解决这种方法遇到的问题,但是您需要提供更多信息。请发布活动的onCreate()和按钮单击处理代码以及布局文件的相关部分。
Graham Borland

@breceivemail我相信TabHost还会使用标记,因此您的用法可能会与它发生冲突。参见grepcode.com/file/repository.grepcode.com/java/ext/…–
爱德华·戴尔

8

您可以尝试重复这种算法“ Android如何找到最匹配的资源” -这非常简单,尤其是当您仅针对不同的屏幕使用不同的布局时。


我试图在android源代码中找到它,但这是本机代码。
Jin35

我认为这更可靠。您可以给我们示例代码作为stackoverflow中的参考吗?:)
Bobs

选择的顺序在这里developer.android.com/guide/topics/resources/… 我想所有这些Context.getResources().getConfiguration()
修饰符

我更喜欢这种方法作为答案。但是它需要一个完整且适用的测试算法。因为@Graham的答案乍看起来似乎不错,但在我的一些复杂活动中遇到了问题。
鲍勃2012年

抱歉,但是我现在没有时间进行测试。如果我做,我会在这里写结果
Jin35

5

我的答案是从@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-xlarge-land”。当我在onCreate()方法中获得标签时,它会给我标签的真实值,例如“ layout-xlarge-land”。但是,当我单击该页面上的按钮并使用该按钮findViewById()并获取其标签时,其值为默认布局标签“ layout”。为什么?????
鲍勃2012年

我在该活动中有一个tabHost。我注意到,tabHost.addTab(myTabSpec);代码行从“ layout-xlarge-land”更改为“ layout”?为什么???
鲍勃2012年

3

我假设您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);
            }
        }
    }
}

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


您的解决方案有问题。旋转屏幕并将布局更改为纵向或横向时,该怎么办?
鲍勃2012年

例如,如果必须将旋转标签更改为“ xlarge-port”后当前标签为“ xlarge-land”
Bobs

所以啊?它会改变(onCreate将再次被调用并设置标签)\
Sherif elKhatib 2012年

你读过我对@Graham答案的评论吗?我认为这些解决方案可能存在我在评论中提到的问题。
Bobs 2012年

我给您2个有效的解决方案。您的评论所指出的情况表明布局是正常的,并且该方法中没有错。试试看他们,如果他们没有工作,我将很乐意为您提供帮助(:
Sherif elKhatib 2012年

2

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

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

在程序中,从textview获取值。我们可以以某种方式了解这种情况。


看看@Graham Borland的答案。这是您的解决方案。并查看评论。在某些情况下,他的解决方案有问题。
鲍勃2012年

2

您可以从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)

1

您的问题与此相同。如何获取布局xml文件路径?
您可以在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的答案。这是您的解决方案。并查看评论。在某些情况下,他的解决方案有问题。
鲍勃2012年

此方法没有错误余量,您将获得准确的值或String,如果正在获取另一个String,则将激活该布局。您要在10英寸平板电脑中使用上述应用程序吗?要激活“ layout-xlarge-land”,您应该在横向模式下使用10英寸平板电脑,请尝试并发布结果。
VenomVendor 2012年

当“活动”具有选项卡时,字符串的值将更改。
鲍勃2012年

将找到解决方案并将其很快发布
VenomVendor 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.