Android原理——动态代码布局

动态代码布局

  1. 如何添加代码布局
  2. 代码布局注意的问题
  3. 代码布局和XML布局的性能比较

如何添加代码布局

for example —— 简单布局LinearLayout

    LinearLayout llayout = new LinearLayout(mContext);
        llayout.setOrientation(LinearLayout.VERTICAL);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.MATCH_PARENT
        );
        llayout.setLayoutParams(layoutParams);

        Button btn = new Button(mContext);
        btn.setText("This is Button");
        btn.setPadding(8, 8, 8, 8);
        btn.setLayoutParams(lp);

        llayout.addView(btn);

        //这是在Activity的onCreate()中设置布局
        setContentView(llayout);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(mContext,
                "This is dynamic activity", Toast.LENGTH_LONG).show();
            }
        });

another example —— 复杂布局RelativeLayout
难点:子控件的相对位置关系的处理

        //父控件
        RelativeLayout myLayout = new RelativeLayout(this);
        myLayout.setBackgroundColor(Color.BLUE); 

        //两个子控件
        Button myButton = new Button(this);
        EditText myEditText = new EditText(this);

        //重点:生成对应的ID
        myButton.setId(generateViewId());
        myEditText.setId(generateViewId());

        //子控件位置
        RelativeLayout.LayoutParams buttonParams =
                new RelativeLayout.LayoutParams(
                        RelativeLayout.LayoutParams.WRAP_CONTENT,
                        RelativeLayout.LayoutParams.WRAP_CONTENT);
        buttonParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
        buttonParams.addRule(RelativeLayout.CENTER_VERTICAL);

        RelativeLayout.LayoutParams textParams =
                new RelativeLayout.LayoutParams(
                        RelativeLayout.LayoutParams.WRAP_CONTENT,
                        RelativeLayout.LayoutParams.WRAP_CONTENT);
        textParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
        textParams.setMargins(0, 0, 0, 80);
        //重点在这里
        textParams.addRule(RelativeLayout.ABOVE, myButton.getId());

        //添加布局
        myLayout.addView(myButton, buttonParams);
        myLayout.addView(myEditText, textParams);
        setContentView(myLayout);

重点要说的是generateViewId(),这个可以专门放到工具类里:

    /**
     * An {@code int} value that may be updated atomically.
     */
    private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);

    /**
     * 动态生成View ID
     * API LEVEL 17 以上View.generateViewId()生成
     * API LEVEL 17 以下需要手动生成
     */
    public static int generateViewId() {

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            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;
                }
            }
        } else {
            return View.generateViewId();
        }
    }

代码布局注意的问题

  • 控件不能重复使用

    // 第一次添加
    mLinearLayout.addView(mTextView, mLayoutParams);
    // 第二次添加
    mLinearLayout.addView(mTextView, mLayoutParams);
    //我们重复添加了两次mTextView。这个是不允许的,在父类布局中,只能有唯一的对象,不能重复。

  • 不同Activity中 Id 相同是否会报错

    直接设置ID setId(1) 是不行的
    生成ID须使用View.generateViewId()
    我的意见是建立静态工具类来生成ID
    关于ID的int相同是否会出错的问题,目前还没有验证

  • 一些常用的代码

    textView.setTextColor(0xffff0000);
    layout.setBackgroundColor(0x00000000);
    setOrientation(LinearLayout.VERTICAL);
    setGravity(Gravity.CENTER_VERTICAL)
    setPadding(10, 5, 5, 5);
    setMargin(8, 0, 0, 0);
    lp.gravity = Gravity.CENTER_VERTICAL;
    lp.topMargin = 5;
    lp.addRule(RelativeLayout.CENTER_VERTICAL);
    lp.addRule(RelativeLayout.RIGHT_OF, ID_IMAGE_HEAD);


代码布局和XML布局的性能比较

测试一个简单的例子

使用代码布局如下:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;

        LinearLayout llayout = new LinearLayout(mContext);
        llayout.setOrientation(LinearLayout.VERTICAL);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.MATCH_PARENT
        );
        llayout.setLayoutParams(layoutParams);

        TextView tv = new TextView(mContext);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
        lp.setMargins(8, 8, 8, 8);

        tv.setLayoutParams(lp);
        tv.setText("This is TextView");
        tv.setPadding(8, 8, 8, 8);

        llayout.addView(tv);

        Button btn = new Button(mContext);
        btn.setText("This is Button");
        btn.setPadding(8, 8, 8, 8);
        btn.setLayoutParams(lp);

        setContentView(llayout);
    }

三次测量平均值: (23+28 + 20)/3 = 23.67ms


使用相同XML布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:text="This is TextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="8px"
        android:padding="8px"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="This is Button"
        android:padding="8px"/>
</LinearLayout>

三次测量平均值: (20 + 26 + 24)/3 = 23.33ms


结论:尽管样本单一,数量也很少,但是说明 代码布局 和 XML布局 加载时间基本相同,性能基本相同。
不足:更复杂的界面,暂时未测试。
想法:代码布局是必要的,如果总结代码布局为模版和库,利用泛型和反射的,在界面的复用和自动化上,将比XML更方便扩展。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。