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


Answers:


117

对于低于Honeycomb(API级别11)的任何内容,您都必须使用setLayoutParams(...)

如果你可以限制你的支持蜂窝最多可以使用setX(...)setY(...)setLeft(...)setTop(...),等。


40
来自setTop()developer.android.com/reference/android/view/…的文档:sets the top position of this view relative to its parent. This method is meant to be called by the layout system and should not generally be called otherwise, because the property may be changed at any time by the layout.-也许那不是一个好主意;)
katzenhut 2014年

47

是的,您可以在Android中动态设置视图的位置。同样,您ImageViewLinearLayoutxml文件中有一个in.so,因此可以通过设置其位置LayoutParams。但是请确保LayoutParams根据xml文件中LayoutParams使用的布局进行选择。根据所使用的布局不同。

这是要设置的代码:

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

希望对您有所帮助。


15
还请注意,您必须导入android.widget.LinearLayout.LayoutParams; 因为默认的是一个ViewGroup的的LayoutParams
大卫吨

这似乎不适用于Android 8+。您是否遇到过类似的问题?
MyFlashLab

知道为什么Andriod设计师会遇到麻烦,以阻止程序员使用X,Y定位事物。最终,所有内容都必须以这种方式绘制。这表明Android是由无法编写代码的人设计的。
保罗·麦卡锡

33

已经有不同的有效答案,但似乎没有一个能正确建议在这种情况下使用哪种方法,除了相应的API级别限制:

  • 如果您可以等待布局周期并且父视图组支持MarginLayoutParams(或子类),请相应地设置marginLeft/ marginTop

  • 如果需要立即且永久地更改位置(例如,对于PopupMenu锚点),请另外layout(l, t, r, b)使用相同的坐标进行调用。这优先于布局系统以后将要确认的内容。

  • 对于即时(临时)更改(例如动画),请使用setX()/ setY()。如果父级大小不取决于WRAP_CHILDREN,则最好使用setX()/ setY()独占。

  • 切勿使用setLeft()/ setRight()/ setBottom()/ setTop(),请参阅下文。

背景:在mLeft/ mTop/ mBottom/ mRight字段将会从相应的LayoutParams填写布局()。布局是由Android视图布局系统隐式和异步调用的。因此,MarginLayoutParams永久设置位置似乎是最安全,最干净的方法。但是,异步布局滞后在某些情况下可能是个问题,例如,使用View渲染光标时,异步布局滞后应重新放置并同时充当PopupMenu锚点。在这种情况下,打电话layout()对我来说很好。

与存在的问题setLeft()setTop()主要有:

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

  • 这些方法的实现看起来相对复杂(=做一些工作来说明由它们各自引起的视图大小变化)

  • 它们似乎在输入字段上引起奇怪的问题:EditText软数字键盘有时不允许数字

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


你好斯特凡。您能不能推荐一些我可以理解android布局系统如何工作的书籍或文章。我了解layout()onMeasure()onDraw()调用的顺序,但想了解更多详细信息。在此先感谢
谢尔盖·布拉

不幸的是,我不能-最好,最
权威的

我使用setY更改视图,是否在下一个布局周期中更改,而不是立即更改?
发出信号

您如何确定的?
Stefan Haustein,

值得指出的是,marginLeft可以通过setLayoutParams与一起设置来new FrameLayout.LayoutParams(width, height)设置marginLeft
lucidbrot

18

有一个名为NineOldAndroids的库,它允许您从第一个版本一直使用Honeycomb动画库。

这意味着您可以使用略有不同的界面定义左,右,translationX / Y。

下面是它的工作原理:

ViewHelper.setTranslationX(view, 50f);

您只需要使用ViewHelper类中的静态方法,传递视图以及要将其设置为哪个值即可。


16

我建议使用 setTranslationXsetTranslationY。我本人只是刚刚开始,但是这些似乎是移动视图的最安全和首选的方式。我想这很大程度上取决于您要尝试执行的操作,但这对于2D动画来说对我来说效果很好。


13

如果您使用的是HoneyComb Sdk(API级别11),则可以尝试使用以下方法。

view.setX(float x);

参数x是此视图的可视x位置。

view.setY(float y);

参数y是此视图的视觉y位置。

希望对您有帮助。:)


4
我正在研究2.2 Froyo,但这些方法不可用。
阿伦·巴多尔

7

为了支持所有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);

以上方法用于设置视图与其父视图相关的位置。


抱歉,这些方法不可用。您可以给我发送任何代码吗?
阿伦·巴多尔

4
“此方法应由布局系统调用,一般不应以其他方式调用,因为该属性可以随时由布局更改。”
GDanger 2014年

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),但不会设置组件的位置,它只会设置组件左边框的位置,其余的将保持在同一位置。


那么如何在不影响原始视图的情况下将视图移动到特定位置?
2016年

我不确定我是否已经理解您的问题,因为如果您要移动视图,则将根据您正在移动的事实对其进行更改。无论如何,如果要独立于另一个视图移动视图,则可能需要一个FrameLayout视图来隐藏主布局,然后可以在其中放置独立视图(显然,如果希望将其移动到主视图下面,必须将FrameLayout放在主要布局之前)
Alessandro Muzzi

3

使用RelativeLayout,将视图放入其中,RelativeLayout.LayoutParams从视图中获取对象并根据需要设置边距。然后调用requestLayout()您的视图。这是我知道的唯一方法。


1

我发现@Stefan Haustein非常接近我的经验,但不确定100%。我的建议是:

  • setLeft()/ setRight()/ setBottom()/ setTop()不会有时工作。
  • 如果要在添加和显示视图临时设置位置(例如,进行动画处理,不影响层次结构),请使用/代替。(您可能希望在搜索更多的差异setX()setY()setLeft()setX()
  • 并注意X,Y似乎是绝对的,并且AbsoluteLayout支持该功能,现在已弃用。因此,您可能不再支持X,Y。是的,是的,但只有一部分。这意味着如果添加了您的视图,则setX(),setY()会完美运行;否则,您尝试将视图添加到视图组布局(例如FrameLayout,LinearLayout,RelativeLayout)时,必须将其LayoutParams 设置marginLeft,marginTop(在这种情况下,setX(),setY()有时将无法工作)。
  • 通过marginLeft和marginTop设置视图的位置是一个不同步的过程。因此需要一点时间来更新层次结构。如果为视图设置边距后立即使用视图,则可能会得到错误的值

0

定位时要记住的一件事是,每个视图都有一个相对于其父视图的索引。因此,如果您具有三个子视图的线性布局,则在上述情况下,每个子视图将具有一个索引:0、1、2。

这样,您可以通过执行以下操作将视图添加到父视图的最后一个位置(或末尾):

int childCount = parent.getChildCount();
parentView.addView(newView, childCount);

另外,您也可以使用以下内容替换视图:

int childIndex = parentView.indexOfChild(childView);
childView.setVisibility(View.GONE);

parentView.addView(newView, childIndex);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.