在Android中如何动态设置视图的位置?

118

我如何通过代码改变视图的位置?比如改变它的X、Y位置。这是可能的吗?

13个回答

123

若要在Honeycomb(API Level 11)及以下版本中使用,您需要使用setLayoutParams(...)

如果您只需支持Honeycomb及更高版本,则可以使用setX(...)setY(...)setLeft(...)setTop(...)等方法。


48
这段话来自于setTop()方法的文档:http://developer.android.com/reference/android/view/View.html#setTop%28int%29。该方法用于设置视图相对于其父容器的顶部位置。这个方法通常应该由布局系统调用,而不应该被其他代码频繁调用,因为该属性可能会被布局系统在任何时候更改。因此,也许并不是一个好主意频繁调用该方法 ;) - katzenhut

51

是的,在Android中可以动态设置视图的位置。同样地,在XML文件中的LinearLayout中有一个ImageView,因此您可以通过LayoutParams设置其位置。但请确保根据XML文件中采用的布局来使用LayoutParams。 根据所采用的布局,有不同的LayoutParams

以下是设置代码:

    LayoutParams layoutParams=new LayoutParams(int width, int height);
    layoutParams.setMargins(int left, int top, int right, int bottom);
    imageView.setLayoutParams(layoutParams);

16
请注意,您必须导入android.widget.LinearLayout.LayoutParams;因为默认的是ViewGroup的LayoutParams。 - David T.
1
这似乎在Android 8+上无法正常工作。你遇到过类似的问题吗? - Hadi tavakoli
1
有没有想过为什么安卓设计师要费这么大的劲来阻止程序员使用X、Y来定位物件。最终所有东西都必须以这种方式绘制。这表明安卓是由不会编程的人设计的。 - Paul McCarthy
如果我们不知道父布局的类型,怎么办? - undefined

44
已经有不同的有效答案了,但是除了相应的API级别限制之外,没有一个正确地建议在哪种情况下使用哪种方法,需要注意以下几点:
  • 如果您可以等待布局周期,并且父视图组支持MarginLayoutParams(或其子类),请相应地设置marginLeft / marginTop

  • 如果您需要立即和持久地更改位置(例如用于弹出菜单锚点),请使用相同的坐标调用layout(l, t, r, b)。这将预先阻止布局系统稍后确认的操作。

  • 对于立即(临时)更改(例如动画),请使用setX() / setY()。在父大小不依赖于WRAP_CHILDREN的情况下,仅使用setX() / setY()可能是可以接受的。

  • 永远不要使用setLeft() / setRight() / setBottom() / setTop(),请参见下文。

背景: mLeft / mTop / mBottom / mRight字段从layout()中的相应LayoutParams中填充。布局由Android视图布局系统隐式异步调用。因此,设置MarginLayoutParams似乎是设置位置的最安全和最清洁的方法。但是,在某些情况下,例如使用View渲染光标,并且它应该同时重新定位并作为弹出菜单锚点,异步布局滞后可能会成为问题。在这种情况下,对我而言,调用layout()效果很好。

setLeft()setTop()的问题是:

  • 仅调用它们是不够的 - 您还需要调用setRight()setBottom()以避免拉伸或缩小视图。

  • 这些方法的实现看起来相对复杂(=执行一些工作以考虑它们引起的视图大小更改)

  • 它们似乎会导致输入字段出现奇怪的问题:EditText软数字键盘有时不允许输入数字

setX()setY()在布局系统之外工作,并且相应的值被视为布局系统确定的左/上/下/右值的附加偏移量,相应地移动视图。它们似乎是为动画添加的(需要立即生效而不经过布局周期)。


你好Stefan。您能给我推荐几本书或文章,让我了解Android布局系统的工作原理吗?我知道layout()、onMeasure()和onDraw()方法的调用顺序,但希望更详细地了解它。提前感谢您。 - Sergey Brazhnik
很遗憾,我不能提供最好和最权威的参考资料,因为它似乎只能在实际的Android源代码中找到 O:) - Stefan Haustein
我使用setY来改变视图,它会在下一个布局周期中改变,而不是立即改变吗? - signal
你是如何确定这个的? - Stefan Haustein
值得指出的是,可以通过使用setLayoutParamsnew FrameLayout.LayoutParams(width, height)来设置marginLeft,从而实现布局。 - lucidbrot
“MarginLayoutParams 或其子类不已经涵盖了这个吗?” - Stefan Haustein

19

有一个名为NineOldAndroids的库,它允许您在所有版本中使用Honeycomb动画库,从版本一开始。

这意味着您可以使用略微不同的接口定义左、右、translationX/Y等参数。

以下是它的工作原理:

ViewHelper.setTranslationX(view, 50f);

你只需要使用ViewHelper类中的静态方法,传递要设置的视图和值即可。


17

我建议使用 setTranslationXsetTranslationY。虽然我自己也只是刚刚开始学习这个,但这似乎是移动视图最安全和首选的方法。我猜这很大程度取决于你具体要做什么,但对于我的2D动画效果而言,这种方法运作良好。


16

如果你正在使用 HoneyComb Sdk(API Level 11),你可以尝试使用以下方法。

view.setX(float x);

参数x是此视图的水平位置。

view.setY(float y);

y参数是视图在y轴上的位置。

希望对您有所帮助。:)


4
我正在使用2.2 Froyo版本,这些方法在其中不可用。 - Arun Badole

8

如果需要支持所有API级别,您可以像这样使用

ViewPropertyAnimator.animate(view).translationYBy(-yourY).translationXBy(-yourX).setDuration(0);

因为他想要改变位置,而且上面的解决方案更好,不需要动画。 - FireZenk
此外,翻译可能会导致视图(部分)超出屏幕。 - mewa

4

将此视图的左侧位置相对于其父级设置:

view.setLeft(int leftPosition);

将此视图相对于其父视图设置正确的位置:

view.setRight(int rightPosition);

设置此视图相对于其父视图的顶部位置:

view.setTop(int topPosition);

将此视图相对于其父视图设置底部位置:

view.setBottom(int bottomPositon);

上述方法用于设置视图相对于其父视图的位置。

抱歉,这些方法不可用。你能发给我任何代码吗? - Arun Badole
5
这个方法是为布局系统设计的,通常情况下不应该被其他代码调用。因为这个属性可能会被布局随时更改。 - GDanger

4

使用LayoutParams。 如果您正在使用LinearLayout,则必须导入android.widget.LinearLayout.LayoutParams,否则导入适合您所使用的布局的正确版本的LayoutParams,否则将会引起ClassCastException,然后:

LayoutParams layoutParams = new LayoutParams(int width, int height);
layoutParams.setMargins(int left, int top, int right, int bottom);
imageView.setLayoutParams(layoutParams);

注意:您也可以使用imageView.setLeft(int dim),但这不会设置组件的位置,它只会设置组件左边框的位置,其余部分仍将保持在相同的位置。

那么我们如何将视图移动到特定位置,而不影响原始视图呢? - james
我不确定我是否理解了你的问题,因为如果你想移动一个视图,你将通过移动它来改变它。无论如何,如果你想独立地在另一个视图上移动一个视图,你可能需要在主布局下面添加一个FrameLayout视图,然后在其中放置你的独立视图(显然,如果你想让它在主视图下面移动,你必须先放置FrameLayout)。 - Alessandro Muzzi

3

在 Kotlin 中,您可以按以下方式完成:

view
    .animate()
    .x(50f)
    .y(100f)
    .duration = 500L

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接