如何在Custom ViewGroup中正确膨胀XML-Layout-File?

我想膨胀自定义ViewGroup类中的XML布局文件,我的问题是,它只产生一个空的屏幕。 在Activity类中做同样的工作很好。 这是我简单的XML布局文件:

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

 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); } } 

这显示了以黑色文本“testing”为中心的白色背景。

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

 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 public class ShowNumber extends Activity {/ **在第一次创build活动时调用。 * /

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ViewGroup vg = new ViewNumber(this); setContentView(vg); } 

}

我这样做基本上就像在这个答案解释。 这只是产生一个空的黑色屏幕。 我做错了什么?

更新1

@Konstantin我应用了你的改变,但仍然只是一个空白的屏幕,我也做了一个日志输出获得的孩子数量。 它始终保持为1,即使我添加一个Textview到XML布局文件。 在更改之前,它始终为0。

 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变化后的Logcat:

 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

内容终于正确显示了。 缺less的是重写RelativeLayout-Sublcass中的onLayout方法(感谢Franco ):

 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); } } ... } 

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

现在,来自Franco的Method initView的解决scheme不会将Center中的TextViewalignment,而是将其放在左上angular。 康斯坦丁的解决scheme正确地把它放在视图的中心:

 public class ViewNumber extends RelativeLayout { ... private void initView(Context context){ View.inflate(context, R.layout.shownumberlayout,this); } ... } 

你试过这个吗?

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

编辑:我快速回应… ViewGroup有责任为他们的孩子准备布局,在布局方法中试试这个:

  @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); } } 

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

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

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

这可能不是你想要的。

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

我build议保持您的自定义视图为RelativeLayout并将您的XML根改为<merge> 。 然后使用添加XML视图到您的父母的膨胀forms – 如View.inflate(context,int,this)

<merge>标签的目的是跳过XML中的根节点。查看它。

你的布局是膨胀无处..使您的ViewNumber扩展FrameLayout并膨胀到它:

 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.. } } 

UPD:你也不需要重写onLayout方法,这看起来很不正确。至less在最开始时调用super.onLayout():

 @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); } 

试试这个:

  LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE ); inflater.inflate( R.layout.login_view_layout, null ); 

onLayout你创build一个ViewNumber( ViewGroup vg = new ViewNumber(this) )的对象的时候,必须重写onLayout ,这就像下面的xml一样:

 <ViewNumber I have no child :( </ViewNumber> 

所以如果你不覆盖onLayout ,ViewNumber的onLayout找不到任何子,那么它将是空白的。

 @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); } 

在覆盖之后,如果你的代码是:ViewNumber的父代,它将使用onLayout方法:

 public class ViewNumber extends RelativeLayout { ... private void initView(Context context){ View.inflate(context, R.layout.shownumberlayout,this); } ... } 

那么就像下面的xml膨胀一样

  <RelativeLayout <RelativeLayout your xml file /> </RelativeLayout> 

还有一个RelativeLayout。为了解决这个问题,你可以写:

 public class ViewNumber extends RelativeLayout { ... private void initView(Context context){ inflater.inflate( R.layout.login_view_layout, null ); //change (..,this) to (..,null) } ... } 

然而,意想不到的事情会发生。 你的xml文件的android:layout_xxx=".."可能会改变(这就是为什么你的文本放在左上angular)。 要了解更多,更好的解决scheme,你可以看到talkol的答案和fgeorgiew的评论:)