首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在自定义ViewGroup中正确地膨胀XML布局文件?

如何在自定义ViewGroup中正确地膨胀XML布局文件?
EN

Stack Overflow用户
提问于 2010-12-15 18:10:05
回答 6查看 83.7K关注 0票数 63

我想在一个自定义的ViewGroup类中膨胀一个XML-Layout-File,我的问题是它只会产生一个空屏幕。在Activity类中执行相同的操作可以很好地工作。下面是我的简单XML-Layout-File:

代码语言:javascript
复制
shownumberlayout.xml:

    <RelativeLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"
        android:background="#FFFFFF" 
        android:id="@+id/layoutForNumber">

        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:id="@+id/tvNumber"
            android:layout_centerHorizontal="true" 
            android:textColor="#000000" 
            android:text="Test" 
            android:layout_centerVertical="true" 
            android:textSize="30dip">
        </TextView>

    </RelativeLayout>

下面是工作版本,在Activity ShowNumber中膨胀shownumberlayout.xml

代码语言:javascript
复制
ShowNumber.class

public class ShowNumber extends Activity {
    /** Called when the activity is first created. */

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        ViewGroup vg = (ViewGroup) inflater.inflate(R.layout.shownumberlayout, null);
        setContentView(vg);
    }
}

这将显示白色背景,黑色文本“Test”居中。

现在,在自定义ViewGroup-Class中膨胀xml的版本:

代码语言:javascript
复制
ViewGroup.class
public class ViewNumber extends ViewGroup {

    private LayoutInflater inflater;

    public ViewNumber(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        initView(context);
    }

    public ViewNumber(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        initView(context);
    }

    public ViewNumber(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub
        initView(context);
    }

    private void initView(Context context){
        inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.shownumberlayout, null);  
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // TODO Auto-generated method stub
    }

}

ShowNumber.class公共类ShowNumber扩展了Activity {首次创建活动时调用的/**。*/

代码语言:javascript
复制
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ViewGroup vg = new ViewNumber(this); 
    setContentView(vg);
}

}

我正在做这件事,基本上就像在this答案解释。这只会产生一个空的黑屏。我做错了什么?

更新1

@Konstantin我应用了您的更改,但仍然只是一个空白屏幕,我还做了一个日志输出来获取孩子的数量。它始终保持为1,即使我向XML-Layout-File中再添加一个Textview。在更改之前,它始终保持为0。

代码语言:javascript
复制
public class ViewNumber extends RelativeLayout {
...
private void initView(Context context){
        //inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        //inflater.inflate(R.layout.shownumberlayout, null);
        View.inflate(context, R.layout.shownumberlayout,this); 
        Log.v("ViewNumber", "Number of Child: " + this.getChildCount());//output is 1,before it remains 0
    }
...
}

@Sankar这是从Konstantin更改后的日志:

代码语言:javascript
复制
12-16 09:24:23.606: DEBUG/AndroidRuntime(8951): >>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<
12-16 09:24:23.606: DEBUG/AndroidRuntime(8951): CheckJNI is OFF
12-16 09:24:23.606: DEBUG/dalvikvm(8951): creating instr width table
12-16 09:24:23.656: DEBUG/AndroidRuntime(8951): --- registering native functions ---
12-16 09:24:23.916: DEBUG/AndroidRuntime(8951): Shutting down VM
12-16 09:24:23.916: DEBUG/dalvikvm(8951): Debugger has detached; object registry had 1 entries
12-16 09:24:23.916: INFO/AndroidRuntime(8951): NOTE: attach of thread 'Binder Thread #3' failed
12-16 09:24:24.076: DEBUG/AndroidRuntime(8960): >>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<
12-16 09:24:24.076: DEBUG/AndroidRuntime(8960): CheckJNI is OFF
12-16 09:24:24.076: DEBUG/dalvikvm(8960): creating instr width table
12-16 09:24:24.126: DEBUG/AndroidRuntime(8960): --- registering native functions ---
12-16 09:24:24.376: INFO/ActivityManager(78): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=org.customview.harold/.ShowNumber }
12-16 09:24:24.426: DEBUG/AndroidRuntime(8960): Shutting down VM
12-16 09:24:24.426: DEBUG/jdwp(8960): Got wake-up signal, bailing out of select
12-16 09:24:24.426: DEBUG/dalvikvm(8960): Debugger has detached; object registry had 1 entries
12-16 09:24:24.456: INFO/AndroidRuntime(8960): NOTE: attach of thread 'Binder Thread #3' failed
12-16 09:24:24.456: VERBOSE/ViewNumber(8923): Number of Child: 1
12-16 09:24:24.496: VERBOSE/RenderScript_jni(164): surfaceDestroyed
12-16 09:24:24.526: INFO/ActivityManager(78): Displayed activity org.customview.harold/.ShowNumber: 104 ms (total 104 ms)
12-16 09:24:24.576: DEBUG/dalvikvm(158): GC_FOR_MALLOC freed 10631 objects / 526248 bytes in 52ms
12-16 09:24:34.606: DEBUG/dalvikvm(164): GC_EXPLICIT freed 1776 objects / 106960 bytes in 91ms

更新2

内容终于正确显示出来了。缺少的是覆盖RelativeLayout-Sublcass中的方法onLayout (感谢Franco):

代码语言:javascript
复制
public class ViewNumber extends RelativeLayout {
...

    @Override
            protected void onLayout(boolean changed, int l, int t, int r, int b) {
                // TODO Auto-generated method stub
                for(int i = 0 ; i < getChildCount() ; i++){
                    getChildAt(i).layout(l, t, r, b);
                }
            }
...
}

注意:稍后您还应该覆盖方法onMeasurement(),但当前内容也可以正确显示,而不会覆盖它。

现在,来自Franco的方法initView的解决方案没有将TextView居中对齐,而是将其放在左上角。来自Konstantin的解决方案将其正确地放在视图的中心:

代码语言:javascript
复制
public class ViewNumber extends RelativeLayout {
...
private void initView(Context context){
        View.inflate(context, R.layout.shownumberlayout,this); 
    }
...
}
EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2010-12-16 10:10:50

你试过这个吗?

代码语言:javascript
复制
private void initView(Context context){
        inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.addView(inflater.inflate(R.layout.shownumberlayout, null));  
    }

编辑:我的反应很快...ViewGroup有责任为他们的孩子准备布局,在layout方法中尝试这样做:

代码语言:javascript
复制
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            // TODO Auto-generated method stub
            for(int i = 0 ; i < getChildCount() ; i++){
                getChildAt(i).layout(l, t, r, b);
            }
        }
票数 33
EN

Stack Overflow用户

发布于 2013-06-18 22:19:07

我不知道这些答案是怎么回事..我认为手动调用onLayout有点疯狂。

LayoutInflater.inflate函数相当简单。如果您使用的是接受第三个布尔参数(attachToRoot)且为的视图,它会将视图从您的XML添加到您的父视图(第二个参数)。如果你使用的是只接受2个参数的函数,如果你提供了一个不是的父函数,那么默认情况下,它会将的真传递给attachToRoot。

在任何情况下,您遇到的大部分混乱都是因为来自XML的视图被添加到了自定义视图中。由于您的XML有一个RelativeLayout根目录,并且您的自定义视图也是一个RelativeLayout,因此您将在相对布局中获得一个相对布局。

这可能不是您想要的。

Konstantin给出的答案是有道理的,但是您正在浪费一个视图,因为您在FrameLayout中放置了一个RelativeLayout。因为Android不能容纳太多的嵌套视图,所以优化并且不添加这个不必要的FrameLayout是一个好主意。

我建议将您的自定义视图保留为RelativeLayout,并将您的XML根目录更改为<merge>。然后使用膨胀表单,它会将XML视图添加到类似于父级的View.inflate(context,int,this)中。

标记的目的是跳过<merge>中的根节点。查一查。

票数 49
EN

Stack Overflow用户

发布于 2010-12-15 19:18:32

你的布局没有任何地方膨胀..使您的ViewNumber扩展FrameLayout并扩展到其中:

代码语言:javascript
复制
public class ViewNumber extends FrameLayout {

    public ViewNumber(Context context) {
        super(context);
        initView(context);
    }

    public ViewNumber(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public ViewNumber(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }

    private void initView(Context context){
        View.inflate(context, R.layout.shownumberlayout, this);  //correct way to inflate..
    }
}

更新:您也不需要重写onLayout方法,这看起来非常不正确。至少在一开始就调用super.onLayout():

代码语言:javascript
复制
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
}
票数 36
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4448779

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档