【问题标题】:How can I dynamically set the position of view in Android?如何在 Android 中动态设置视图的位置?
【发布时间】:2011-09-26 00:16:53
【问题描述】:

如何通过代码改变视图的位置?就像改变它的 X、Y 位置一样。有可能吗?

【问题讨论】:

    标签: android layout view


    【解决方案1】:

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

    如果您可以限制对 Honeycomb 及更高版本的支持,您可以使用 setX(...)、setY(...)、setLeft(...)、setTop(...) 等。

    【讨论】:

    • 来自 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. - 所以也许这不是一个好主意 ;)
    【解决方案2】:

    是的,您可以在 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);
    

    【讨论】:

    • 还要注意必须import android.widget.LinearLayout.LayoutParams;因为默认是ViewGroup的LayoutParams
    • 这似乎不适用于 Android 8+。你遇到过类似的问题吗?
    • 知道为什么 Andriod 的设计师会费尽心思阻止程序员使用 X、Y 来定位东西。最终,一切都必须以这种方式绘制。这表明 Android 是由不会编码的人设计的。
    【解决方案3】:

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

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

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

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

    • 从不使用setLeft() / setRight() / setBottom() / setTop(),见下文。

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

    setLeft() 和 setTop() 的问题是:

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

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

    • 它们似乎会导致输入字段出现奇怪的问题:EditText soft numeric keyboard sometimes does not allow digits

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

    【讨论】:

    • 你好斯特凡。你能推荐几本书或文章,让我了解 android 布局系统是如何工作的。我了解 layout() onMeasure() onDraw() 调用的顺序,但想了解更多细节。提前致谢
    • 很遗憾我不能——最好和最权威的参考似乎是实际的 Android 源代码 O:)
    • 我使用 setY 来改变视图,它会在下一个布局周期中改变,而不是立即改变?
    • 你是如何确定的?
    • 值得指出的是,marginLeft 可以通过使用 setLayoutParams 和您设置 marginLeft 的 new FrameLayout.LayoutParams(width, height) 来设置
    【解决方案4】:

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

    这意味着您可以使用稍微不同的界面定义左、右、平移X/Y。

    这是它的工作原理:

    ViewHelper.setTranslationX(view, 50f);
    

    您只需使用 ViewHelper 类中的静态方法,传递视图以及您想要设置的值。

    【讨论】:

      【解决方案5】:

      我建议使用setTranslationX 和setTranslationY。我自己才刚刚开始,但这些似乎是移动视图的最安全和首选的方式。我想这在很大程度上取决于您到底想要做什么,但这对我来说非常适合 2D 动画。

      【讨论】:

        【解决方案6】:

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

        view.setX(float x);
        

        参数x是这个视图的视觉x位置。

        view.setY(float y);
        

        参数y是这个视图的视觉y位置。

        希望对你有所帮助。 :)

        【讨论】:

        • 我正在开发 2.2 Froyo,这些方法在其中不可用。
        【解决方案7】:

        要支持所有 API 级别,您可以像这样使用it:

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

        【讨论】:

        • 因为他想改变位置,上面的解决方案更好,不需要动画
        • 另外,翻译可能会导致视图(部分)离开屏幕
        【解决方案8】:

        使用布局参数。 如果您使用的是 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),但是这不会设置组件的位置,它只会设置组件左边框的位置,其余的将保持在同一位置。

        【讨论】:

        • 那么我们如何在不影响原始视图的情况下将视图移动到特定位置?
        • 我不确定我是否理解你的问题,因为如果你想移动一个视图,你会因为你正在移动它而改变它。无论如何,如果您想将一个视图独立于另一个视图移动,您可能需要一个 FrameLayout 视图来破坏您的主布局,然后在其中放置您的独立视图(显然,如果您希望它在您的主视图下移动必须将 FrameLayout 放在主要的之前)
        【解决方案9】:

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

        【讨论】:

          【解决方案10】:

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

          view.setLeft(int leftPosition);
          

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

          view.setRight(int rightPosition);
          

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

          view.setTop(int topPosition);
          

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

          view.setBottom(int bottomPositon);
          

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

          【讨论】:

          • 对不起,这些方法不可用。你能把代码发给我吗?
          • "这个方法是由布局系统调用的,一般不应该调用,因为这个属性可能随时被布局改变。"
          【解决方案11】:

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

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

          【讨论】:

            【解决方案12】:

            在 Kotlin 中,您可以按以下方式进行操作;

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

            【讨论】:

              【解决方案13】:

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

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

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

              或者,您可以使用以下内容替换视图:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多