简析静态xml布局如何通过动态代码实现
Posted 开心每一日
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简析静态xml布局如何通过动态代码实现相关的知识,希望对你有一定的参考价值。
先看一下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);
}
}
最后的效果展示图:
以上是关于简析静态xml布局如何通过动态代码实现的主要内容,如果未能解决你的问题,请参考以下文章
在Android中,如何将数据从类传递到相应的布局/片段文件?