Как правильно накачать XML-Layout-File внутри Custom ViewGroup? - PullRequest
58 голосов
/ 15 декабря 2010

Я хочу надуть XML-Layout-File в пользовательском классе ViewGroup, моя проблема в том, что он создает только пустой экран. Делать то же самое в классе деятельности работает нормально. Вот мой простой 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>

Вот рабочая версия, раздувающая shownumberlayout.xml в Деятельности 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);
    }
}

Показывает белый фон с черным текстом «Test» по центру.

Теперь версия, раздувающая xml в пользовательском ViewGroup -Классе:

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 extends Activity { / ** Вызывается при первом создании действия. * /

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

}

Я делаю это в основном как в этом Ответ объяснил. Это просто производит пустой черный экран. Что я делаю не так?

ОБНОВЛЕНИЕ 1

@ Константин Я применил ваши изменения, но все еще на пустом экране, я также сделал лог-вывод для получения количества детей. Это остается всегда 1, даже я добавляю еще один Textview к XML-Layout-File. До Изменений всегда остается 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
    }
...
}

@ Санкар Это 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

Контент, наконец, отображается правильно. Пропущено было переопределить метод onLayout (благодаря Franco ) в 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);
                }
            }
...
}

Примечание. Позже вам также следует переопределить метод onMeasurement(), но в настоящее время содержимое также отображается правильно, без переопределения.

Теперь решение для метода initView из Franco не выравнивает TextView по центру, а помещает его в верхний левый угол. Решение от Константин правильно размещает его в центре вида:

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

Ответы [ 5 ]

43 голосов
/ 18 июня 2013

Я не знаю, что происходит в этих ответах ... Я думаю, что вручную вызывать onLayout - это немного сумасшествие.

Функция LayoutInflater.inflate довольно проста.Если вы используете тот, который принимает третий логический аргумент (attachToRoot) и он true , он добавит представления из вашего XML в родительское представление (2-й аргумент).Если вы используете тот, который принимает только 2 аргумента, он будет передавать true в attachToRoot по умолчанию, если вы предоставите родителя, который не является null .

В любом случае, большая часть беспорядка, который вы испытываете, связана с тем, что представления из вашего XML добавляются в ваш пользовательский вид.Поскольку у вашего XML есть корень RelativeLayout, а пользовательское представление также RelativeLayout - вы получаете относительный макет внутри относительного макета.

Это, вероятно, не то, что вы хотите.

Ответ, данный Константином, имеет смысл, но вы теряете представление, потому что вы помещаете RelativeLayoutвнутри FrameLayout.Поскольку Android не может содержать слишком много вложенных представлений, рекомендуется оптимизировать, а не добавлять это ненужное FrameLayout.

. Я предлагаю оставить ваше настраиваемое представление равным RelativeLayout и изменить корень XML на * 1027.*.Затем воспользуйтесь формой inflate, которая добавляет представления XML к вашему родителю - например, View.inflate(context,int,this)

Цель тега <merge> состоит в том, чтобы пропустить корневой узел в XML .. посмотреть его.

34 голосов
/ 15 декабря 2010

Ваш макет нигде не надувается. Заставьте 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, который выглядит очень некорректно ... по крайней мере, вызовите super.onLayout () при самом запуске:

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
}
29 голосов
/ 16 декабря 2010

Вы пробовали это?

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);
            }
        }
1 голос
/ 06 августа 2015

Переопределение onLayout необходимо. Когда вы создаете объект ViewNumber (ViewGroup vg = new ViewNumber(this)), это похоже на раздувание xml ниже:

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

, поэтому, если вы не переопределите onLayout,onLayout ViewNumber не может найти ни одного потомка, тогда он будет пустым.

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

после переопределения, он будет использовать метод onLayout родительского элемента ViewNumber, если ваши коды:

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

Однако произойдет что-то неожиданное. android:layout_xxx=".." вашего xml файла может измениться (вот почему ваш текст помещается в верхний левый угол).Чтобы узнать больше и найти лучшее решение, вы можете увидеть ответ talkol 'и комментарий fgeorgiew :)

1 голос
/ 22 июня 2015

Попробуйте это:

 LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
 inflater.inflate( R.layout.login_view_layout, null );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...