Определение размера представления Android во время выполнения



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



это кажется легкой задачей, и есть много так вопросов относительно этого, хотя никто что, очевидно, решило мою проблему. Так что, возможно, я упускаю что-то очевидное. Я получаю ручку к моему взгляду:



ImageView myView = (ImageView)getWindow().findViewById(R.id.MyViewID);


это работает нормально, но при вызове getWidth(),getHeight(),getMeasuredWidth(),getLayoutParams().width и т. д. все они возвращают 0. Я также попытался вручную позвонить measure() на вид с последующим вызовом getMeasuredWidth(), но это не имеет никакого эффекта.



Я попытался вызвать эти методы и проверить объект в отладчике в моей деятельности onCreate() и onPostCreate(). Как может Я выясняю точные размеры этого представления во время выполнения?

781   10  

10 ответов:

используйте ViewTreeObserver на представлении, чтобы дождаться первого макета. Только после того, как первый макет будет getWidth()/getHeight()/getMeasuredWidth()/getMeasuredHeight() работы.

ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
  viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
      view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
      viewWidth = view.getWidth();
      viewHeight = view.getHeight();
    }
  });
}

Существует несколько решений, в зависимости от сценария:

  1. безопасный метод, будет работать непосредственно перед рисованием Вида, после завершения этапа компоновки:
public static void runJustBeforeBeingDrawn(final View view, final Runnable runnable) {
    final OnPreDrawListener preDrawListener = new OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            view.getViewTreeObserver().removeOnPreDrawListener(this);
            runnable.run();
            return true;
        }
    };
    view.getViewTreeObserver().addOnPreDrawListener(preDrawListener); }

пример использования:

    ViewUtil.runJustBeforeBeingDrawn(yourView, new Runnable() {
        @Override
        public void run() {
            //Here you can safely get the view size (use "getWidth" and "getHeight"), and do whatever you wish with it
        }
    });
  1. в некоторых случаях, достаточно измерить размер вручную:
view.measure(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
int width=view.getMeasuredWidth(); 
int height=view.getMeasuredHeight();
  1. если у вас есть пользовательский вид, который вы расширили, вы можете получите его размер по методу "onMeasure", но я думаю, что он хорошо работает только в некоторых случаях:
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
    final int newHeight= MeasureSpec.getSize(heightMeasureSpec);
    final int newWidth= MeasureSpec.getSize(widthMeasureSpec);
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
  1. если вы пишете в Kotlin, вы можете использовать следующую функцию, которая за кулисами работает точно так же, как runJustBeforeBeingDrawn что я написал:

    view.doOnPreDraw { actionToBeTriggered() }
    

    обратите внимание, что вам нужно добавить это в gradle (найдено через здесь):

    implementation 'androidx.core:core-ktx:#.#'
    

ты называешь getWidth() прежде чем вид на самом деле выложен на экране?

распространенной ошибкой новых разработчиков Android является использование ширины и высота вида внутри его конструктора. Когда представление конструктор называется, Android еще не знает, насколько большой вид будет быть, поэтому размеры установлены на ноль. Реальные размеры рассчитываются во время этап компоновки, который происходит после строительства, но перед чем-либо почерпнутый. Вы можете использовать onSizeChanged() метод уведомления значения, когда они известны, или вы можете использовать getWidth() и getHeight() методы позже, например в onDraw() метод.

на основе рекомендаций @mbaird, я нашел приемлемое решение путем создания подклассов ImageView класса и переопределение onLayout(). Затем я создал интерфейс наблюдателя, который моя активность реализовала и передала ссылку на себя классу, что позволило ему сообщить активность, когда она была фактически завершена.

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

вот код для получения макета путем переопределения представления, если API

public class CustomListView extends ListView
{
    private OnLayoutChangedListener layoutChangedListener;

    public CustomListView(Context context)
    {
        super(context);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b)
    {
        if (layoutChangedListener != null)
        {
            layoutChangedListener.onLayout(changed, l, t, r, b);
        }
        super.onLayout(changed, l, t, r, b);
    }

    public void setLayoutChangedListener(
        OnLayoutChangedListener layoutChangedListener)
    {
        this.layoutChangedListener = layoutChangedListener;
    }
}
public interface OnLayoutChangedListener
{
    void onLayout(boolean changed, int l, int t, int r, int b);
}

вы можете проверить этот вопрос. Вы можете использовать View ' s post () метод.

это работает для меня в моем onClickListener:

yourView.postDelayed(new Runnable() {               
    @Override
    public void run() {         
        yourView.invalidate();
        System.out.println("Height yourView: " + yourView.getHeight());
        System.out.println("Width yourView: " + yourView.getWidth());               
    }
}, 1);

Я тоже потерялся вокруг getMeasuredWidth() и getMeasuredHeight()getHeight() и getWidth() в течение длительного времени.......... позже я обнаружил, что получение ширины и высоты в onSizeChanged() это лучший способ, чтобы сделать это........ вы можете динамически получить текущую ширину и текущую высоту вашего представления, переопределив onSizeChanged() метод.

возможно, вы захотите взглянуть на это, у которого есть сложный фрагмент кода. Новое сообщение в блоге: Как получить размеры ширины и высоты customView (extends View) в Android http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions.html

используйте ниже код, это дает размер представления.

@Override
public void onWindowFocusChanged(boolean hasFocus) {
       super.onWindowFocusChanged(hasFocus);
       Log.e("WIDTH",""+view.getWidth());
       Log.e("HEIGHT",""+view.getHeight());
}

работает perfekt для меня:

 protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);
        CTEditor ctEdit = Element as CTEditor;
        if (ctEdit == null) return;           
        if (e.PropertyName == "Text")
        {
            double xHeight = Element.Height;
            double aHaight = Control.Height;
            double height;                
            Control.Measure(LayoutParams.MatchParent,LayoutParams.WrapContent);
            height = Control.MeasuredHeight;
            height = xHeight / aHaight * height;
            if (Element.HeightRequest != height)
                Element.HeightRequest = height;
        }
    }

Comments

    Ничего не найдено.