使用 LayoutParams.addRule 设置动态设置视图到视图的最后位置

Setting views dynamically with LayoutParams.addRule setting to the last position of the view

我正在向相对布局动态添加视图并以编程方式定义它们。视图可以在屏幕上移动,因此它们的位置会发生变化。

当我尝试将视图 (button2) 设置为位于另一个视图 (button1) 下方时,button2 被放置在 button1 的旧位置(在移动之前添加视图的默认位置)。我已经链接了图片,希望能更好地传达这一点。

这是原始布局

Button2重新定位后的布局

我有一个后台 LinkedList,用于跟踪布局的所有视图更改和视图属性(如果有差异的话)。

以下是代码函数:

我如何重新定位 Button1:

Buttons b = (Buttons) viewIndex;
                                positioningLayout = new RelativeLayout.LayoutParams(b.getLayoutParams());
                                positioningLayout.addRule(RelativeLayout.CENTER_VERTICAL);
                                b.setLayoutParams(positioningLayout);
                                baseLayout.addView(b);

在另一个视图下方重新定位视图代码片段:

Buttons b = (Buttons) viewIndex;
                                positioningLayout = new RelativeLayout.LayoutParams(b.getLayoutParams());
                                positioningLayout.addRule(RelativeLayout.BELOW, viewIdFromList.intValue());
                                b.setLayoutParams(positioningLayout);
                                b.invalidate();

我如何将视图添加到布局中。

uiList.addView(new Buttons(this), "BUTTON");
            setDialogView(uiList.getLast());
            showDialog(SET_ID);
            reloadUI();

setDialogView 只是将视图传递给对话框 SET_ID 以便我可以手动为视图分配一个 ID(用于测试)。 reloadUI() 只是找到最后添加到后台 LinkedList 的视图,并将其添加到 relativeLayout using .addView;

如果您需要更多代码,请告诉我。在对 relativeLayout 子视图进行更改后,我是否错过了更新视图布局的调用?看起来视图在视觉上正在重新定位,但实际的 LayoutParams 没有更新,所以当您将 Button2 设置为 Button1 时,它正在获得旧位置。

有没有办法强制重新定位相对布局视图?

您似乎走对了路,但犯了一个小错误。如果没有更多代码,就很难提供实际的解决方案。不过我会尽量指出错误的。

看,要在 RelativeLayout 中以编程方式相对定位项目,您必须 为每个项目分配唯一 ID

喜欢,

Button b = new Button(this);
b.setId(1);

Button c = new Button(this);
c.setId(2);

每个元素都应该有唯一的 ID。

现在如果要将按钮 b 垂直放置在中央,

layout.addRule(RelativeLayout.CENTER_VERTICAL);
b.setLayoutParams(layout);

现在如果你想把 Button c 放在它下面,

layout.addRule(RelativeLayout.BELOW, b.getId());
layout.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
b.setLayoutparams(layout);

这肯定会将按钮 c 放在按钮 b 的下方。正如您所说,您可以使用您选择的任何数据结构来跟踪每个元素的 ID。

这只是关于如何正确移动按钮的详细示例。所以首先,为 View 创建一个唯一的 id,即在 res/values/ 中创建一个新的 XML 资源文件,并将其命名为 ids.xml:

ids.xml的内容是:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="button_1" type="id"/>
    <item name="button_2" type="id"/>
</resources>

我们必须为您的主布局设置一个 id:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/layout_main"> <!-- the id -->

    <!-- content of this layout -->

</RelativeLayout>

然后,让我们创建 Buttons:

    RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.layout_main);

    final Button button1 = new Button(this);
    button1.setId(R.id.button_1);
    button1.setText("BUTTON 1");
    button1.setTextColor(Color.BLACK);

    final Button button2 = new Button(this);
    button2.setId(R.id.button_2);
    button2.setText("BUTTON 2");
    button2.setTextColor(Color.BLACK);

    relativeLayout.addView(button1, new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
            RelativeLayout.LayoutParams.WRAP_CONTENT));
    relativeLayout.addView(button2, new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
            RelativeLayout.LayoutParams.WRAP_CONTENT));

    RelativeLayout.LayoutParams params1 = (RelativeLayout.LayoutParams) button1.getLayoutParams();
    params1.addRule(RelativeLayout.CENTER_IN_PARENT); // set to the center of screen
    button1.setLayoutParams(params1);

    final RelativeLayout.LayoutParams params2 = (RelativeLayout.LayoutParams) button2.getLayoutParams();
    params2.addRule(RelativeLayout.ALIGN_PARENT_TOP);
    params2.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
    button2.setLayoutParams(params2);

    button2.setOnClickListener(new View.OnClickListener() {
        @SuppressLint("NewApi")
        @Override
        public void onClick(View v) {
            /* We need to remove the existing rules and update it!
             * For API 16 and earlier, set the rule to 0, e.g. --> layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
             * For API 17 and higher, call layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_LEFT);
             */

            int api = android.os.Build.VERSION.SDK_INT;
            if (api >= Build.VERSION_CODES.JELLY_BEAN_MR1) { // API level 17
                params2.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
                params2.removeRule(RelativeLayout.ALIGN_PARENT_LEFT);
            }else if (api < Build.VERSION_CODES.JELLY_BEAN_MR1) {
                params2.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
                params2.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
            }

            params2.addRule(RelativeLayout.CENTER_IN_PARENT);
            params2.addRule(RelativeLayout.BELOW, R.id.button_1); // place below button1
            button2.setLayoutParams(params2);
        }
    });

所以一旦你点击 button2,它就会移到 button1 下面。

我认为您应该尝试简单的解决方案 - 将 b.invalidate() 替换为 b.requestLayout()。如需更多背景调查 this link。我没有测试它,但我希望它会起作用。所以代码应该是这样的:

Buttons b = (Buttons) viewIndex;
positioningLayout = new RelativeLayout.LayoutParams(b.getLayoutParams());
positioningLayout.addRule(RelativeLayout.BELOW, viewIdFromList.intValue());
b.setLayoutParams(positioningLayout);
b.requestLayout();

或者您可以将其简化为:

Buttons b = (Buttons) viewIndex;
((RelativeLayout.LayoutParams) b.getLayoutParams()).addRule(RelativeLayout.BELOW, viewIdFromList.intValue());
b.requestLayout();