Android:在绘制之前获取视图的高度
Posted
技术标签:
【中文标题】Android:在绘制之前获取视图的高度【英文标题】:Android: get height of a view before it´s drawn 【发布时间】:2012-03-23 11:01:48 【问题描述】:对于动画,我需要知道视图的高度。问题是,除非绘制视图,否则 getHeight() 方法总是返回 0。 那么有没有什么办法不用画就可以得到高度呢?
在这种情况下,视图是一个线性布局。
编辑: 我尝试从 https://github.com/Udinic/SmallExamples/blob/master/ExpandAnimationExample/src/com/udinic/expand_animation_example/ExpandAnimation.java 改编扩展动画
有了它,我想为列表项扩展更多信息。 我无法通过 xml 达到相同的效果。 目前动画只有在绘制之前知道布局大小时才有效。
【问题讨论】:
【参考方案1】:听起来您想获取高度,但在视图可见之前将其隐藏。
将视图中的可见性设置为可见或不可见(只是为了创建一个高度)。不用担心我们会在代码中将其更改为不可见/消失,如下所示:
private int mHeight = 0;
private View mView;
class...
// onCreate or onResume or onStart ...
mView = findViewByID(R.id.someID);
mView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener()
@Override
public void onGlobalLayout()
// gets called after layout has been done but before display
// so we can get the height then hide the view
mHeight = mView.getHeight(); // Ahaha! Gotcha
mView.getViewTreeObserver().removeGlobalOnLayoutListener( this );
mView.setVisibility( View.GONE );
);
【讨论】:
【参考方案2】:我遇到了类似情况的类似问题。
我必须创建一个动画,我需要 view
的高度受动画影响。在view
中,这是一个LinearLayout
可能是TextView
类型的子视图。 TextView
是多行,实际需要的行数会有所不同。
无论我做什么,我都只是得到了视图的测量高度,好像TextView
只需要填充一行。难怪每次当文本恰好足够短到一行时,这都能正常工作,但当文本长于一行时,它就会失败。
我考虑过这个答案:https://***.com/a/6157820/854396
但是那个对我来说效果不太好,因为我无法直接从这里访问嵌入式TextView
。 (虽然我可以迭代子视图树。)
看看我的代码,因为它现在可以工作:
view
是要设置动画的视图。这是一个LinearLayout
(最终的解决方案将在这里保存更多类型)
this
是一个自定义视图,包含 view
并且也继承自 LinearLayout
。
private void expandView( final View view )
view.setVisibility(View.VISIBLE);
LayoutParams parms = (LayoutParams) view.getLayoutParams();
final int width = this.getWidth() - parms.leftMargin - parms.rightMargin;
view.measure( MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
final int targetHeight = view.getMeasuredHeight();
view.getLayoutParams().height = 0;
Animation anim = new Animation()
@Override
protected void applyTransformation( float interpolatedTime, Transformation trans )
view.getLayoutParams().height = (int) (targetHeight * interpolatedTime);
view.requestLayout();
@Override
public boolean willChangeBounds()
return true;
;
anim.setDuration( ANIMATION_DURATION );
view.startAnimation( anim );
差不多了,但我又犯了一个错误。在视图层次结构中,涉及两个自定义视图,它们是LinearLayout
的子类,它们的 xml 与 merge
标记合并为 xml 根标记。在这些merge
标记之一中,我忽略了将android:orientation
属性设置为vertical
。
这对布局本身并没有太大影响,因为在这个合并的ViewGroup
中只有一个孩子ViewGroup
,因此我实际上无法在屏幕上看到错误的方向。但它就在那里,有点打破了这种布局测量逻辑。
除了上述之外,可能还需要删除与LinearLayout
s 和视图层次结构中的子类相关的所有填充。用边距替换它们,即使您必须围绕它包装另一个布局以使其看起来相同。
【讨论】:
【参考方案3】:从技术上讲,您可以在视图上调用measure
方法,然后通过getMeasureHeight
获取它的高度。有关更多信息,请参阅:https://developer.android.com/guide/topics/ui/how-android-draws.html。不过你需要给它一个MeasureSpec
。
但实际上,视图的大小受其父布局的影响,因此您可能会得到与实际绘制时不同的大小。
另外,您可以尝试在动画中使用 RELATIVE_TO_SELF
值。
【讨论】:
【参考方案4】:static void getMeasurments(View v)
v.measure(View.MeasureSpec.makeMeasureSpec(PARENT_VIEW.getWidth(),
View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED));
final int targetHeight = v.getMeasuredHeight();
final int targetWidth = v.getMesauredWidth();
【讨论】:
【参考方案5】:如果父母没有确定它的大小,就自己测量吧:
这里有一个 kotlin 扩展,可以随时为你做这件事:
fun View.getMeasurments(): Pair<Int, Int>
measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
val width = measuredWidth
val height = measuredHeight
return width to height
【讨论】:
【参考方案6】:虽然this answer 一开始似乎有效,但最终我注意到它弄乱了正在测量的视图。 我通过传递父视图来修复它。
/**
* class to map width and height values.
*/
data class Point(val width: Int, val height: Int)
/**
* Measures the view and returns the width and height.
*/
fun View.getMeasurements(parent: View): Point
measure(View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(parent.height, View.MeasureSpec.UNSPECIFIED))
return Point(measuredWidth, measuredHeight)
我还创建了一个数据类,因此值所代表的内容变得更具可读性。 您现在可以像这样访问结果值
child.getMeasurements(parent).width
或者这个
child.getMeasurements(parent).height
【讨论】:
【参考方案7】:好的,关于更新后的帖子,以下内容将对您有所帮助: Animation#initialize 方法。你应该把初始化而不是构造函数放在那里,你就会有你需要的所有大小。
【讨论】:
【参考方案8】:您可以尝试从 View 可见开始,然后添加如下内容:
view.post(new Runnable()
@Override
public void run()
// hide view here so that its height has been already computed
view.setVisibility(View.GONE);
);
现在,当您调用 view.getHeight() 时,它应该返回您期望的高度。
我不确定这是否真的是一个好方法,但至少它应该有效。
【讨论】:
以上是关于Android:在绘制之前获取视图的高度的主要内容,如果未能解决你的问题,请参考以下文章
如何在xml中设置复合可绘制文本视图的高度和宽度? [关闭]