先看一下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); } }
最后的效果展示图: