android - layout_weight - ¿Cómo inflar XML-Layout-File correctamente dentro de Custom ViewGroup?
table layout android (5)
Quiero inflar un XML-Layout-File en una clase de ViewGroup personalizada, mi problema es que produce solo una pantalla vacía. Hacer lo mismo en la clase de actividad funciona bien. Aquí está mi simple XML-Layout-File:
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>
Aquí está la Versión de trabajo, inflando el shownumberlayout.xml
en el 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);
}
}
Esto muestra un fondo blanco con el texto negro "Test" centrado.
Ahora la Versión inflar el xml en el Custom ViewGroup
-Class:
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 {/ ** Llamada cuando la actividad se crea por primera vez. * /
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewGroup vg = new ViewNumber(this);
setContentView(vg);
}
}
Lo estoy haciendo básicamente como en this Respuesta explicada. Esto solo produce una Pantalla Negra Vacía. ¿Que estoy haciendo mal?
ACTUALIZACIÓN 1
@Konstantin Apliqué tus cambios pero solo una pantalla en blanco, también hice una salida de registro para obtener el número de hijos. Siempre permanece 1, incluso agrego una Textview más al XML-Layout-File. Antes de los cambios, siempre permanece 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 Este es el Logcat, después de los cambios de Konstantin:
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
ACTUALIZACIÓN 2
El contenido finalmente se muestra correctamente. Lo que faltaba era anular el Método en onLayout
(gracias a Franco ) en RelativeLayout-Sublcass:
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);
}
}
...
}
Nota: Más tarde también debe anular el Método en la onMeasurement()
, pero actualmente el contenido también se muestra correctamente sin anularlo.
Ahora la solución para el Método initView
de Franco no alinea el TextView en el Centro, sino que lo coloca en la esquina superior izquierda. La solución de Konstantin lo coloca correctamente en el centro de la vista:
public class ViewNumber extends RelativeLayout {
...
private void initView(Context context){
View.inflate(context, R.layout.shownumberlayout,this);
}
...
}
¿Has intentado esto?
private void initView(Context context){
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.addView(inflater.inflate(R.layout.shownumberlayout, null));
}
EDITAR: Respondo rápidamente ... un ViewGroup tiene la responsabilidad de preparar el diseño para sus hijos, en el método de diseño intente esto:
@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);
}
}
No sé qué está pasando en estas respuestas ... Creo que llamar a onLayout
manualmente está un poco loco.
La función LayoutInflater.inflate
es bastante directa. Si está utilizando el que acepta el tercer argumento booleano (attachToRoot) y es verdadero , agregará las vistas de su XML a su vista principal (el segundo argumento). Si está utilizando el que acepta solo 2 argumentos, pasará true a attachToRoot de forma predeterminada si proporciona un elemento primario que no sea nulo .
En cualquier caso, la mayor parte del problema que está experimentando se debe a que las vistas de su XML se agregan a su vista personalizada. Dado que su XML tiene una raíz RelativeLayout
y su vista personalizada también es RelativeLayout
, obtendrá un diseño relativo dentro de un diseño relativo.
Esto probablemente no es lo que quieres.
La respuesta dada por Konstantin tiene sentido, pero estás desperdiciando una vista porque estás colocando un RelativeLayout
dentro de FrameLayout
. Como Android no puede contener demasiadas vistas anidadas, es una buena idea optimizar y no agregar este FrameLayout
innecesario.
Sugiero mantener su vista personalizada como RelativeLayout
y cambiar su raíz XML a <merge>
. A continuación, utilice el formulario de View.inflate(context,int,this)
que agrega las vistas XML a su elemento primario, como View.inflate(context,int,this)
El objetivo de la etiqueta <merge>
es omitir el nodo raíz en el XML. Búsquelo.
Prueba este:
LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
inflater.inflate( R.layout.login_view_layout, null );
Su diseño está inflado en ninguna parte ... haga que su ViewNumber amplíe FrameLayout e infle en él:
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: tampoco es necesario que anule el método de encendido, que se ve muy incorrecto ... al menos llame a super.onLayout () desde el principio:
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
onLayout
es necesario. Cuando crea un objeto de ViewNumber ( ViewGroup vg = new ViewNumber(this)
), es como inflar xml a continuación:
<ViewNumber
I have no child :(
</ViewNumber>
por lo tanto, si no sobrescribe en onLayout
, ViewNumber''s onLayout
no puede encontrar ningún elemento secundario, entonces estará en blanco.
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
después de anular, usará el método onLayout del padre de ViewNumber, si sus códigos son:
public class ViewNumber extends RelativeLayout {
...
private void initView(Context context){
View.inflate(context, R.layout.shownumberlayout,this);
}
...
}
entonces es como inflar xml a continuación
<RelativeLayout
<RelativeLayout
your xml file
/>
</RelativeLayout>
hay un RelativeLayout más. Para escribir esto, puede escribir:
public class ViewNumber extends RelativeLayout {
...
private void initView(Context context){
inflater.inflate( R.layout.login_view_layout, null );
//change (..,this) to (..,null)
}
...
}
Sin embargo, algo inesperado sucederá. android:layout_xxx=".."
de su archivo xml puede cambiar (esta es la razón por la que su texto se coloca en la esquina superior izquierda). Para obtener más información y una mejor solución, puede ver la respuesta de talkol y el comentario de fgeorgiew debajo de ella :)