为包含的布局的后代分配唯一ID

时间:2015-04-25 11:53:18

标签: android android-layout

我有以下布局设置(我省略了不相关的标签):

main.xml:
<include
    android:id="@+id/test1"
    layout="@layout/mylayout"
    />

<include
    android:id="@+id/test2"
    layout="@layout/mylayout"
    />

mylayout.xml:
<LinearLayout
    <EditText
        android:id="@+id/myedittext"
    />
</LinearLayout>

请注意,此特定示例至关重要过度简化,我的实际mylayout.xml很复杂,并且包含大量带有大量ID的子布局和子视图,我会真的不喜欢将其内联到main.xml

所以,我想多次重复使用布局mylayout.xml。您可能会注意到两个EditTexts将具有重复的ID。这似乎不是问题,因为我只在活动初始​​化时使用R.id.myedittext来查找test1test2布局为findViewById的根的视图,之后我直接通过View对象访问这些EditTexts。我发现Butterknife非常方便,代码看起来像这样:

class LayoutHolder {
     @InjectView(R.id.myedittext)
     EditText editText;
     // ...
     static LayoutHolder create(View root) {
         LayoutHolder holder = new LayoutHolder();
         ButterKnife.inject(holder, root);
         return holder;
     }
}

当我尝试更改屏幕方向时出现问题:由于这些非唯一ID,两个EditTexts都恢复了相同的状态。好吧,我想,我只需要在values目录中定义一些ID,然后在EditTexts上使用View.setId方法。但是这种方法存在一些问题:特别是,我必须为mylayout.xml内的ID的每个视图手动和编程设置这些ID。更重要的是,即使我这样做,我也不能再以统一的方式访问这些子视图,因为它们都会有不同的ID(特别是,我不能做这些不错的Butterknife注射)

我已经找到了解决这个问题的其他方法,但它们更加复杂和丑陋。那么,是否有一些很好的通用方法来满足我的需求呢?我不知道我在网上找不到任何东西,因为重复使用布局以避免代码重复(实际上是xml复制,但无论如何)看起来很自然。

2 个答案:

答案 0 :(得分:0)

我一直在使用我在开源项目中找到的代码。

public class Utils {

    private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
     /**
     * Generate a value suitable for use in setId(int}.
     * This value will not collide with ID values generated at build time by aapt for R.id.
     *
     * @return a generated ID value
     */
    private static int generateViewId() {
        for (; ; ) {
            final int result = sNextGeneratedId.get();
            // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
            int newValue = result + 1;
            if (newValue > 0x00FFFFFF) {
                newValue = 1; // Roll over to 1, not 0.
            }
            if (sNextGeneratedId.compareAndSet(result, newValue)) {
                return result;
            }
        }
    }

    @SuppressLint("NewApi")
    public static int generateId() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {

            return generateViewId();
        }
        else {

            return View.generateViewId();
        }
    }
}

答案 1 :(得分:0)

修补黄油刀,所以它会支持两个这样的ID

@InjectView(R.id.mylayout, R.id.myedittext)