简析静态xml布局如何通过动态代码实现

来源:互联网 发布:淘宝我的爱车 编辑:程序博客网 时间:2024/05/16 08:47

先看一下xml代码:

<?xml version="1.0" encoding="utf-8"?><LinearLayout    android:id="@+id/contentView"    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="horizontal">    <!--静态xml加载部分-->    <LinearLayout        android:id="@+id/ll01"        android:layout_width="0dp"        android:background="@android:color/holo_orange_dark"        android:layout_height="wrap_content"        android:layout_weight="1"        android:orientation="vertical">        <TextView            android:id="@+id/tv_static_loading"            android:layout_width="150dp"            android:layout_height="wrap_content"            android:layout_gravity="right"            android:layout_marginTop="10dp"            android:text="我是静态xml加载的布局"/>        <TextView            android:layout_width="150dp"            android:layout_height="wrap_content"            android:layout_marginTop="10dp"            android:gravity="center"            android:text="静态xml加载的布局"/>        <Button            android:layout_width="150dp"            android:layout_height="wrap_content"            android:layout_marginTop="10dp"            android:gravity="left|center"            android:text="按钮1"/>        <ImageView            android:layout_width="150dp"            android:layout_height="150dp"            android:scaleType="fitCenter"            android:src="@mipmap/q01"/>        <TextView            android:id="@+id/tv_margin"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginLeft="10dp"            android:background="#000"            android:text="marginLeft为10dp"            android:textColor="#fff"            android:textSize="20sp"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:paddingLeft="20dp"            android:background="#000"            android:text="padLeft为20dp"            android:textColor="#fff"            android:textSize="20sp"/>    </LinearLayout>    <!--动态xml加载部分-->  <!--  <LinearLayout        android:layout_width="0dp"        android:layout_weight="1"        android:layout_height="wrap_content">    </LinearLayout>--></LinearLayout>



<LinearLayout        android:id="@+id/ll01"        android:layout_width="0dp"        android:layout_height="wrap_content"        android:layout_weight="1"        android:orientation="vertical">
将会从此处开始用动态代码重复下面的写法,当然也少不了一些说明。

整体架构如下:

<?xml version="1.0" encoding="utf-8"?><LinearLayout    android:id="@+id/contentView"    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="horizontal">    <!--静态xml加载部分-->    <LinearLayout        android:id="@+id/ll01"        android:layout_width="0dp"        android:background="@android:color/holo_orange_dark"        android:layout_height="wrap_content"        android:layout_weight="1"        android:orientation="vertical">        <TextView            android:id="@+id/tv_static_loading"            android:layout_width="150dp"            android:layout_height="wrap_content"            android:layout_gravity="right"            android:layout_marginTop="10dp"            android:text="我是静态xml加载的布局"/>        <TextView            android:layout_width="150dp"            android:layout_height="wrap_content"            android:layout_marginTop="10dp"            android:gravity="center"            android:text="静态xml加载的布局"/>        <Button            android:layout_width="150dp"            android:layout_height="wrap_content"            android:layout_marginTop="10dp"            android:gravity="left|center"            android:text="按钮1"/>        <ImageView            android:layout_width="150dp"            android:layout_height="150dp"            android:scaleType="fitCenter"            android:src="@mipmap/q01"/>        <TextView            android:id="@+id/tv_margin"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginLeft="10dp"            android:background="#000"            android:text="marginLeft为10dp"            android:textColor="#fff"            android:textSize="20sp"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:paddingLeft="20dp"            android:background="#000"            android:text="padLeft为20dp"            android:textColor="#fff"            android:textSize="20sp"/>    </LinearLayout>    <!--动态xml加载部分-->  <!--  <LinearLayout        android:layout_width="0dp"        android:layout_weight="1"        android:layout_height="wrap_content">    </LinearLayout>--></LinearLayout>





会看到布局文件中有宽度和字体大小单位分别是dp和sp,然而动态加载时,只能以px为单位,因此,我们先把单位初始化为px单位,看mian.java:

package com.demo.linearlayoutdemo;import android.graphics.Color;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.TypedValue;import android.view.ViewGroup;import android.widget.LinearLayout;import android.widget.TextView;public class MainLLDemoActivity extends AppCompatActivity {    /**     * 150dp对应的px值     */    private int on150Dp;    /**     * 1dp = ?px     */    private int perDp;    private int on10Dp;    private int on20Dp;    private float on20Sp ;    private TextView tvStaticLoading;    private TextView tvMargin;    private ViewGroup contentView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main_lldemo);        tvStaticLoading = (TextView) findViewById(R.id.tv_static_loading);        tvMargin = (TextView) findViewById(R.id.tv_margin);        contentView = (ViewGroup) findViewById(R.id.contentView);    }    @Override    public void onWindowFocusChanged(boolean hasFocus) {        on150Dp = tvStaticLoading.getWidth();        perDp = on150Dp / 150;        on10Dp = perDp * 10;        on20Dp = perDp * 20;        on20Sp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20,                getResources().getDisplayMetrics());    }}

此处,我们分2个方法拿到dp和sp,在这里会看到,博主是

@Override    public void onWindowFocusChanged(boolean hasFocus) {    }
在这个方法里面取值,因为在onCreate中是取不到值得。看看以下这个与众不同的取法。

     on20Sp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20,             getResources().getDisplayMetrics());
这个方法也是用于将dp和sp转换成对应的尺寸,看看TypedValue.applyDimension做了啥:

    /**     * Converts an unpacked complex data value holding a dimension to its final floating      * point value. The two parameters <var>unit</var> and <var>value</var>     * are as in {@link #TYPE_DIMENSION}.     *       * @param unit The unit to convert from.     * @param value The value to apply the unit to.     * @param metrics Current display metrics to use in the conversion --      *                supplies display density and scaling information.     *      * @return The complex floating point value multiplied by the appropriate      * metrics depending on its unit.      */    public static float applyDimension(int unit, float value,                                       DisplayMetrics metrics)    {        switch (unit) {        case COMPLEX_UNIT_PX:            return value;        case COMPLEX_UNIT_DIP:            return value * metrics.density;        case COMPLEX_UNIT_SP:            return value * metrics.scaledDensity;        case COMPLEX_UNIT_PT:            return value * metrics.xdpi * (1.0f/72);        case COMPLEX_UNIT_IN:            return value * metrics.xdpi;        case COMPLEX_UNIT_MM:            return value * metrics.xdpi * (1.0f/25.4f);        }        return 0;    }
可以看出,他是将对应的px,dp,sp,pt,in,mm转换成对应的尺寸,其中dp和px有一个叫density系数维系关系,sp和对应的尺寸也有一个scaledDensity系数维系关系。
好的,现在开始说说动态代码写布局的实现方式了。之前说过了,在onCreate的时候是得不到对应的dp和sp值得,所以我们在得到值后再动态加载。

    @Override    public void onWindowFocusChanged(boolean hasFocus) {        on150Dp = tvStaticLoading.getWidth();        perDp = on150Dp / 150;        on10Dp = perDp * 10;        on20Dp = perDp * 20;        dynamicXML();    }    private void dynamicXML() {            }

此时,先看看开始的效果:




这是一开始的部分:

    <LinearLayout        android:id="@+id/ll01"        android:layout_width="0dp"        android:background="@android:color/holo_orange_dark"        android:layout_height="wrap_content"        android:layout_weight="1"        android:orientation="vertical">
动态写法:

    private void dynamicXML() {        LinearLayout topLL = getLinearLayout();    }    private LinearLayout getLinearLayout(){        LinearLayout ll = new LinearLayout(this);        LinearLayout.LayoutParams lllp = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT,1);        contentView.addView(ll,lllp);        ll.setBackgroundColor(Color.BLUE);        ll.setOrientation(LinearLayout.VERTICAL);        return ll;    }
此时,看看效果如何:


LinearLayout.LayoutParams lllp = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT,1);
对应的参数分别如下:

(int width, int height, float weight) 
这就相当于静态xml的如下写法:

 <LinearLayout        android:layout_width="0dp"        android:layout_height="wrap_content"        android:layout_weight="1"
将布局添加到xml布局中,最上层的那个LInearLayout,contentView的排序是横向方式,将背景设置成蓝色,排序方式设置为纵向,反正就是和上述的xml一样。
        contentView.addView(ll,lllp);        ll.setBackgroundColor(Color.BLUE);        ll.setOrientation(LinearLayout.VERTICAL);

接下来,要实现这1个

        <TextView            android:id="@+id/tv_static_loading"            android:layout_width="150dp"            android:layout_height="wrap_content"            android:layout_gravity="right"            android:layout_marginTop="10dp"            android:text="我是静态xml加载的布局"/>

    private void dynamicXML() {        LinearLayout topLL = getLinearLayout();        setTextViewOne(topLL);    }    private void setTextViewOne(ViewGroup vp){        TextView textView = new TextView(this);        LinearLayout.LayoutParams ll= new LinearLayout.LayoutParams(on150Dp, ViewGroup.LayoutParams.WRAP_CONTENT);        ll.gravity = Gravity.RIGHT;        textView.setBackgroundColor(Color.WHITE);        ll.setMargins(0,on10Dp,0,0);        textView.setText("我是动态加载的布局");        vp.addView(textView,ll);    }
效果图如下:


将“我是动态加载的布局”,改成和上面一样后,在看看效果:



这里的效果和左边的一样,150DP刚好是那字体的长度。

然后再写:

       <TextView            android:layout_width="150dp"            android:layout_height="wrap_content"            android:layout_marginTop="10dp"            android:gravity="center"            android:text="静态xml加载的布局"/>

把tv1和tv2的一起看

    private LinearLayout getLinearLayout(){        LinearLayout ll = new LinearLayout(this);        LinearLayout.LayoutParams lllp = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT,1);        contentView.addView(ll,lllp);        ll.setBackgroundColor(Color.BLUE);        ll.setOrientation(LinearLayout.VERTICAL);        return ll;    }    private void setTextViewOne(ViewGroup vp){        TextView textView = new TextView(this);        LinearLayout.LayoutParams ll= new LinearLayout.LayoutParams(on150Dp, ViewGroup.LayoutParams.WRAP_CONTENT);        ll.gravity = Gravity.RIGHT;        ll.setMargins(0,on10Dp,0,0);        textView.setText("我是动态加载的布局");        vp.addView(textView,ll);    }    private void setTextViewTwo(ViewGroup vp){        TextView textView = new TextView(this);        LinearLayout.LayoutParams ll= new LinearLayout.LayoutParams(on150Dp, ViewGroup.LayoutParams.WRAP_CONTENT);        ll.setMargins(0,on10Dp,0,0);        textView.setText("我也是动态加载的布局");        textView.setGravity(Gravity.CENTER);        vp.addView(textView,ll);    }
在One的方法,是调用了ll.gravity,而Two的方法,则是调用textview.gravity,然后在看看xml上的差异。

        <TextView            android:id="@+id/tv_static_loading"            android:layout_width="150dp"            android:layout_height="wrap_content"            android:layout_gravity="right"            android:layout_marginTop="10dp"            android:text="我是静态xml加载的布局"/>        <TextView            android:layout_width="150dp"            android:layout_height="wrap_content"            android:layout_marginTop="10dp"            android:gravity="center"            android:text="静态xml加载的布局"/>
可以看到,如果是
            android:layout_gravity="right"
则调用ll.gravity,如果是
            android:gravity="center"
则调用textview.gravity,得出一个规律就是,凡是android:layout_打头的属性,都要用LayoutParams调用,在这里因为父布局是LInearLayout,所以用到LinearLayout.LayoutParams。

接下来动态设置下面这2个控件:

        <Button            android:layout_width="150dp"            android:layout_height="wrap_content"            android:layout_marginTop="10dp"            android:gravity="left|center"            android:text="按钮1"/>        <ImageView            android:layout_width="150dp"            android:layout_height="150dp"            android:scaleType="fitCenter"            android:src="@mipmap/q01"/>

添加代码如下:

    private void setButton(ViewGroup vp){        Button btn = new Button(this);        LinearLayout.LayoutParams ll = new LinearLayout.LayoutParams(on150Dp, ViewGroup.LayoutParams.WRAP_CONTENT);        ll.setMargins(0,on10Dp,0,0);        btn.setGravity(Gravity.LEFT|Gravity.CENTER);        btn.setText("按钮1");        vp.addView(btn,ll);    }    private void setImageView(ViewGroup vp){        ImageView iv = new ImageView(this);        LinearLayout.LayoutParams ll = new LinearLayout.LayoutParams(on150Dp, on150Dp);        iv.setScaleType(ImageView.ScaleType.FIT_CENTER);        iv.setImageResource(R.mipmap.q01);        vp.addView(iv,ll);    }
调用方法也是雷同的:

    private void dynamicXML() {        LinearLayout topLL = getLinearLayout();        setTextViewOne(topLL);        setTextViewTwo(topLL);        setButton(topLL);        setImageView(topLL);    }

此时,看看效果图:


会发现蓝色部分的按钮比较奇葩,那是因为通过xml设置的button默认会加上一个选择器,我们也通过代码给奇葩的button加上一个选择器看看:

        btn.setBackgroundResource(android.R.drawable.btn_default);
此时,再看看效果图:



正常了吧!

最后2个了,先看看他们的静态设置:

        <TextView            android:id="@+id/tv_margin"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginLeft="10dp"            android:background="#000"            android:text="marginLeft为10dp"            android:textColor="#fff"            android:textSize="20sp"/>        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:paddingLeft="20dp"            android:background="#000"            android:text="padLeft为20dp"            android:textColor="#fff"            android:textSize="20sp"/>
先设置倒数第二个的动态加载:

    private void setLastButOne(ViewGroup vp){        TextView tv = new TextView(this);        LinearLayout.LayoutParams ll = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,                ViewGroup.LayoutParams.WRAP_CONTENT);        ll.setMargins(on10Dp,0,0,0);        tv.setBackgroundColor(Color.rgb(0,0,0));        tv.setText("marginLeft为10dp");        tv.setTextColor(Color.rgb(0xff,0xff,0xff));        tv.setTextSize(on20Sp);        vp.addView(tv,ll);    }
再看看效果图:



会发现,设置的on20Sp好像不太给力,然后再将它设置成:

        tv.setTextSize(20);
再看看效果图:

此刻好像20也是对应20SP,为什么sp可以这样设置,而没有直接设置dp的方法,看看源码的setTextSize是怎样的:

    public void setTextSize(float size) {        setTextSize(TypedValue.COMPLEX_UNIT_SP, size);    }
会看到,原来他已经把20转换成SP单位了,所以设置字体大小的时候不用我们操心了!

最后一步的代码则是:

    private void setLastOne(ViewGroup vp){        TextView tv = new TextView(this);        LinearLayout.LayoutParams ll = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,                ViewGroup.LayoutParams.WRAP_CONTENT);        tv.setPadding(on20Dp,0,0,0);        tv.setBackgroundColor(Color.rgb(0,0,0));        tv.setText("padLeft为20dp");        tv.setTextColor(Color.rgb(0xff,0xff,0xff));        tv.setTextSize(20);        vp.addView(tv,ll);    }
此时注意padding和margin的区别:

在xml上:

            android:layout_marginLeft="10dp"
            android:paddingLeft="20dp"
一个是android:layout_开头的,一个则不是,根据上面说到的,也可以猜到代码的写法了。

        ll.setMargins(on10Dp,0,0,0);
        tv.setPadding(on20Dp,0,0,0);


好的,就说到这里了,附上全部代码。

xml文章开头就有了,因此这里附上的是main.java文件的代码:

package com.demo.linearlayoutdemo;import android.graphics.Color;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.TypedValue;import android.view.Gravity;import android.view.ViewGroup;import android.widget.Button;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.TextView;import android.widget.Toast;public class MainLLDemoActivity extends AppCompatActivity {    /**     * 150dp对应的px值     */    private int on150Dp;    /**     * 1dp = ?px     */    private int perDp;    private int on10Dp;    private int on20Dp;    private float on20Sp ;    private TextView tvStaticLoading;    private TextView tvMargin;    private ViewGroup contentView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main_lldemo);        tvStaticLoading = (TextView) findViewById(R.id.tv_static_loading);        tvMargin = (TextView) findViewById(R.id.tv_margin);        contentView = (ViewGroup) findViewById(R.id.contentView);    }    @Override    public void onWindowFocusChanged(boolean hasFocus) {        on150Dp = tvStaticLoading.getWidth();        perDp = on150Dp / 150;        on10Dp = perDp * 10;        on20Dp = perDp * 20;        on20Sp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20,                getResources().getDisplayMetrics());        dynamicXML();        Toast.makeText(this, "tvMargin.getTextSize():" + tvMargin.getTextSize(), Toast.LENGTH_SHORT).show();    }    private void dynamicXML() {        LinearLayout topLL = getLinearLayout();        setTextViewOne(topLL);        setTextViewTwo(topLL);        setButton(topLL);        setImageView(topLL);        setLastButOne(topLL);        setLastOne(topLL);    }    private LinearLayout getLinearLayout(){        LinearLayout ll = new LinearLayout(this);        LinearLayout.LayoutParams lllp = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT,1);        contentView.addView(ll,lllp);        ll.setBackgroundColor(Color.rgb(0,0,255));        ll.setOrientation(LinearLayout.VERTICAL);        return ll;    }    private void setTextViewOne(ViewGroup vp){        TextView textView = new TextView(this);        LinearLayout.LayoutParams ll= new LinearLayout.LayoutParams(on150Dp, ViewGroup.LayoutParams.WRAP_CONTENT);        ll.gravity = Gravity.RIGHT;        ll.setMargins(0,on10Dp,0,0);        textView.setText("我是动态加载的布局");        vp.addView(textView,ll);    }    private void setTextViewTwo(ViewGroup vp){        TextView textView = new TextView(this);        LinearLayout.LayoutParams ll= new LinearLayout.LayoutParams(on150Dp, ViewGroup.LayoutParams.WRAP_CONTENT);        ll.setMargins(0,on10Dp,0,0);        textView.setText("我也是动态加载的布局");        textView.setGravity(Gravity.CENTER);        vp.addView(textView,ll);    }    private void setButton(ViewGroup vp){        Button btn = new Button(this);        LinearLayout.LayoutParams ll = new LinearLayout.LayoutParams(on150Dp, ViewGroup.LayoutParams.WRAP_CONTENT);        ll.setMargins(0,on10Dp,0,0);        btn.setGravity(Gravity.LEFT|Gravity.CENTER);        btn.setText("按钮1");        btn.setBackgroundResource(android.R.drawable.btn_default);        vp.addView(btn,ll);    }    private void setImageView(ViewGroup vp){        ImageView iv = new ImageView(this);        LinearLayout.LayoutParams ll = new LinearLayout.LayoutParams(on150Dp, on150Dp);        iv.setScaleType(ImageView.ScaleType.FIT_CENTER);        iv.setImageResource(R.mipmap.q01);        vp.addView(iv,ll);    }    private void setLastButOne(ViewGroup vp){        TextView tv = new TextView(this);        LinearLayout.LayoutParams ll = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,                ViewGroup.LayoutParams.WRAP_CONTENT);        ll.setMargins(on10Dp,0,0,0);        tv.setBackgroundColor(Color.rgb(0,0,0));        tv.setText("marginLeft为10dp");        tv.setTextColor(Color.rgb(0xff,0xff,0xff));        tv.setTextSize(20);        vp.addView(tv,ll);    }    private void setLastOne(ViewGroup vp){        TextView tv = new TextView(this);        LinearLayout.LayoutParams ll = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,                ViewGroup.LayoutParams.WRAP_CONTENT);        tv.setPadding(on20Dp,0,0,0);        tv.setBackgroundColor(Color.rgb(0,0,0));        tv.setText("padLeft为20dp");        tv.setTextColor(Color.rgb(0xff,0xff,0xff));        tv.setTextSize(20);        vp.addView(tv,ll);    }}

最后的效果展示图:







0 0
原创粉丝点击