Android: нужно использовать onSizeChanged для View.getWidth/Height() в классе, расширяющем Activity

Я хочу использовать getWidth()/getHeight(), чтобы получить ширину/высоту моего XML-макета. Я читал, что должен сделать это в методе onSizeChanged(), иначе я получу 0 (Android: получить разрешение экрана/пиксели как целочисленные значения).

Но я хочу сделать это в классе, уже расширяющем Activity. Поэтому я думаю, что это невозможно, чтобы тот же класс расширял View.

public class MyClass extends Activity {

    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        ViewGroup xml_layout = (ViewGroup) findViewById(R.id.layout_id);  
        TextView tv = new TextView(this);  
        tv = (TextView) findViewById(R.id.text_view);  
        int layout_height = xml_layout.getHeight();  
        int layout_width = xml_layout.getWidth();
    }  

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        //Error, because I need to use extends View for class, but I can't do it because I also need extends Activity to use onCreate
    }
}

Если я использую MyClass extends Activity, я могу использовать onCreate, но не onSizeChanged.
Если я использую MyClass extends View, я могу использовать onSizeChangedbut, а не onCreate.

Как я могу решить проблему?

Ответы

Ответ 1

Вам не нужно создавать customView, чтобы получить его высоту и ширину. Вы можете добавить OnLayoutChangedListener (описание здесь) к представлению, ширина/высота которого вы хотите, а затем по существу получить значения в методе onLayoutChanged, например так

View myView = findViewById(R.id.my_view);
myView.addOnLayoutChangeListener(new OnLayoutChangeListener() {

        @Override
        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight,
                int oldBottom) {
            // its possible that the layout is not complete in which case
            // we will get all zero values for the positions, so ignore the event
            if (left == 0 && top == 0 && right == 0 && bottom == 0) {
                return;
            }

           // Do what you need to do with the height/width since they are now set
        }
    });

Причиной этого является то, что представления отображаются только после завершения макета. Затем система спускается вниз по дереву представлений heirarchy, чтобы измерить ширину/высоту каждого вида перед их рисованием.

Ответ 2

То, что я бы рекомендовал сделать, - это расширить ListView в своем собственном классе. Определите класс MyListView или что-то подобное, и убедитесь, что вы определяете все три конструктора. Затем переопределите метод onSizeChanged, чтобы вызвать что-то извне - это похоже на OnClickListener или OnTouchListener. Вы можете определить метод в MyListView, чтобы принять слушателя, создать экземпляр слушателя в вашей деятельности, а затем, когда вызывается onSizeChanged, передайте его слушателю. Это действительно трудно объяснить на английском языке. Вот пример кода:

Пользовательский ListView:

public class MyListView extends ListView
{
    public MyListView(Context context)
    {
        super(context);
    }
    public MyListView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }
    public MyListView(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    public void SetOnResizeListener(MyOnResizeListener orlExt)
    {
        orl = orlExt;
    }

    @Override
    protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld)
    {
        super.onSizeChanged(xNew, yNew, xOld, yOld);

        if(orl != null)
        {
            orl.OnResize(this.getId(), xNew, yNew, xOld, yOld);
        }
    }

    MyOnResizeListener orl = null;
 }

Пользовательский прослушиватель:

public class MyOnResizeListener
 {
    public MyOnResizeListener(){}

    public void OnResize(int id, int xNew, int yNew, int xOld, int yOld){}
 }

Вы создаете экземпляр слушателя, как:

Class MyActivity extends Activity
{
      /***Stuff***/

     MyOnResizeListener orlResized = new MyOnResizeListener()
     {
          @Override
          public void OnResize(int id, int xNew, int yNew, int xOld, int yOld)
          {
           /***Handle resize event****/
          }
     };
}

И не забудьте передать слушателю свой пользовательский вид:

 /***Probably in your activity onCreate***/
 ((MyListView)findViewById(R.id.MyList)).SetOnResizeListener(orlResized);

Наконец, вы можете добавить свой собственный список в макет XML, выполнив что-то вроде:

 <com.myapplication.whatever.MyListView>
      <!-- Attributes -->
 <com.myapplication.whatever.MyListView/>

Ответ 3

У меня была аналогичная проблема (т.е. вычисление размеров View в Activity после завершения рисования).

Я перепробовал метод Activity: public void onWindowFocusChanged(boolean hasFocus) и он работал нормально.

Ответ 4

Просто добавьте метод в свое настраиваемое представление, которое вы вызываете, когда onSizeChanged имеет место в Activity. Передайте новые значения в представление как параметры вызываемого метода. Затем выполните все операции, которые необходимо выполнить, когда пользовательский вид изменит размер.