Android: как получить доступ к ресурсам xml из раздутого пользовательского компонента

Я новичок в Android и пытаюсь создать собственный компонент в своем приложении для Android. Для этого я расширяю FrameLayout, чтобы мой пользовательский компонент мог состоять из счетчика поверх представления (со временем я буду рисовать в представлении, но в данный момент оно просто пустое).

В моем классе, который расширяет FrameLayout, я хотел бы настроить кнопку счетчика, которую я разместил в xml. Однако вызов findViewById из этого класса возвращает значение null. Прочитав здесь ответы на похожие проблемы, я понял, что мне нужно вызвать findViewById из действия (и действительно, если я настрою счетчик из класс, расширяющий активность, все работает нормально). Тогда одним из решений было бы передать действие конструктору моего класса FrameLayout. Однако я никогда не вызываю конструктор своего класса FrameLayout сам, потому что использую layoutinflater для его надувания. Я предполагаю, что компоновщик вызывает конструктор моего класса FrameLayout, и я не уверен, как добавить аргумент к его вызову конструктора.

Может ли кто-нибудь сказать мне, что я делаю неправильно, или как я должен подходить к этому?

Вот упрощенная версия моего кода:

Мой собственный класс FrameLayout:

package com.example.myoscilloscope.gui;

import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.FrameLayout;
import android.widget.Spinner;

import com.example.myoscilloscope.R;

public class Oscilloscope extends FrameLayout {

    //variables
    private Spinner chanSelector; //the channel selector

    // overloading constructors
    public Oscilloscope(Context context) { this(context, null, 0); }
    public Oscilloscope(Context context, AttributeSet attrs) { this(context, attrs, 0); }

    public Oscilloscope(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

            //set up the spinner.
            chanSelector = (Spinner) findViewById(R.id.channel_spinner);

            if(chanSelector == null){
                Log.d("FROMTOM", "CHANNELSELECTOR IS NULL!");
            }

    }

}

Мой класс активности огромен, но осциллограф надувается при нажатии кнопки, поэтому соответствующий раздел (я думаю):

import com.example.myoscilloscope.gui.Oscilloscope;

// ...

public void addchannel(View v){ 
    //this initialization is actually done elsewhere, but I've copied it here
    //  for simplicity's sake
    private LayoutInflater oscilloscopeInflater; 
    LinearLayout myOscilloscopeHolder;

    oscilloscopeInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    myOscilloscopeHolder = (LinearLayout)findViewById(R.id.oscilloscopeHolder); 

    Oscilloscope myOscilliscope = (Oscilloscope)oscilloscopeInflater.inflate(R.layout.oscilloscope, myOscilloscopeHolder, false);       
    myOscilloscopeHolder.addView(trOscilloscopes[trChannelsDisplayed]);
}

Вот мой файл Oscilloscope.xml, который раздувается моей основной программой:

<?xml version="1.0" encoding="utf-8"?>
<com.example.myoscilloscope.gui.Oscilloscope xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/oscilloscope"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1" >

    <com.example.myoscilloscope.gui.Oscillator
        android:id="@+id/oscillator"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

       <Spinner 
        android:id="@+id/channel_spinner"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
    />


</com.example.myoscilloscope.gui.Oscilloscope>

И вот соответствующий фрагмент моего main.xml:

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/background_color" >

    <LinearLayout
        android:id="@id/oscilloscopeHolder"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_above="@id/rg_channels"
        android:layout_toLeftOf="@id/HistogramArea"
        android:orientation="vertical"
        android:background="#FFFFFF" >


    </LinearLayout>
</RelativeLayout>

Надеюсь, это имеет смысл. Любые идеи будут высоко оценены.

Том


person ForeverWintr    schedule 22.03.2012    source источник


Ответы (2)


К сожалению, извините, я не заметил, что это были разные взгляды ... это должно решить вашу проблему.

Вы не должны использовать findViewById в конструкторе, потому что на этом этапе инфляция еще не завершена. Переместите код findViewById в переопределенную функцию с именем onFinishInflate().

    public class Oscilloscope extends FrameLayout {

        private Spinner chanSelector; //the channel selector

        public Oscilloscope(Context context) { this(context, null, 0); }
        public Oscilloscope(Context context, AttributeSet attrs) { this(context, attrs, 0); }
        public Oscilloscope(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }

        @Override
        public void onFinishInflate(){
                super.onFinishInflate();        

                chanSelector = (Spinner) findViewById(R.id.channel_spinner);

                if (chanSelector == null) {
                    //Should never get here
                }
        }
    }
person Bobbake4    schedule 22.03.2012
comment
Спасибо за ответ. Если вы получаете уведомление каждый раз, когда я пытаюсь ответить на этот вопрос; оказывается, я не могу понять, как вставить код в комментарий. Извини за это. Во всяком случае, я сделал, как вы предлагаете, и переменная chanSelector по-прежнему возвращается как нулевая. Любые другие идеи? - person ForeverWintr; 23.03.2012
comment
Конечно, помогает, если идентификатор, который вы указываете в xml, совпадает с идентификатором, который вы ищете в findViewById... это была моя другая проблема. После исправления собственной глупости ваше решение работает! Спасибо. - person ForeverWintr; 23.03.2012

Вы можете перебирать детей с...

getChildCount();
getChildAt(index);

Затем вы можете сравнить дочерние идентификаторы с тем, что вы ищете.

person CaseyB    schedule 22.03.2012
comment
Боюсь, я не понимаю; не могли бы вы уточнить? - person ForeverWintr; 23.03.2012