天天看点

android—代码动态布局笔记

       在android项目中,大多数界面布局都是通过.xml文件布局的,少部分情况,或者一些特殊项目的需求会使用到代码动态布局。写这篇博客的目的主要是为了记录自己在项目中经常使用动态布局,偶尔会遇到一些版本适配和布局差异的问题。以此记录,在下次遇到的时候方便查阅。从使用角度来分析,动态布局是要比常规的静态布局(.xml)更为复杂一些,而且限制也比较多。首次接触,可以先写出静态布局,再根据API转化成动态布局。

      下面我们先来看一个比较简单的静态布局和动态布局的对照比较:

效果图:

android—代码动态布局笔记

静态布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/darker_gray"
    android:orientation="vertical" >

    <ImageView
        android:layout_width="90dp"
        android:layout_height="90dp"
        android:layout_gravity="left"
        android:src="@drawable/v" />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:hint="static layout!" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/bt1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="delete all" />

        <Button
            android:id="@+id/bt2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="search answer" />
    </LinearLayout>

</LinearLayout>
           

动态布局代码:

public class DynamicView extends LinearLayout {

	public DynamicView(Context context) {
		this(context, null);
	}

	public DynamicView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
		this.setOrientation(LinearLayout.VERTICAL);
		this.setBackgroundColor(Color.GRAY);
		// photo
		ImageView imageView = new ImageView(context);
		imageView.setBackgroundResource(R.drawable.v);
		LinearLayout.LayoutParams imageViewParams = new LinearLayout.LayoutParams(dip2px(context, 90),
				dip2px(context, 90));
		imageViewParams.gravity = Gravity.LEFT;
		this.addView(imageView, imageViewParams);
		// input
		EditText editText = new EditText(context);
		editText.setHint("static layout!");
		LinearLayout.LayoutParams editTextParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.WRAP_CONTENT);
		editTextParams.topMargin = dip2px(context, 5);
		this.addView(editText, editTextParams);

		LinearLayout linearLayout = new LinearLayout(context);
		linearLayout.setOrientation(LinearLayout.HORIZONTAL);
		LinearLayout.LayoutParams linearLayoutParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.WRAP_CONTENT);
		// but1
		Button button1 = new Button(context);
		button1.setText("delete all");
		LinearLayout.LayoutParams button1Params = new LinearLayout.LayoutParams(dip2px(context, 0),
				LayoutParams.WRAP_CONTENT);
		button1Params.weight = 1;
		linearLayout.addView(button1, button1Params);
		// but2
		Button button2 = new Button(context);
		button2.setText("search answer");
		LinearLayout.LayoutParams button2Params = new LinearLayout.LayoutParams(dip2px(context, 0),
				LayoutParams.WRAP_CONTENT);
		button2Params.weight = 1;
		linearLayout.addView(button2, button2Params);

		this.addView(linearLayout, linearLayoutParams);
	}

	/**
	 * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
	 */
	public static int dip2px(Context context, float dpValue) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (dpValue * scale + 0.5f);
	}
}
           

       如上,我们大概可以简单的对比出两种布局的一些实现差异。整个流程下来,静态布局确实简单了很多。动态布局则需要对布局控件api的一些基本属性有所认知,更重要的是要考虑,它的一个层次规范。从另外一个角度来说,静态布局我们可以在书写过程中,可以随时查看他的展示而做出调整,动态布局就不行,只能是通过运行结果,来做调整,整个过程也变得更为麻烦。

接下来,是我在动态布局中遇到的一些问题,在此罗列,希望在下次碰到的时候,可以直接搬过去用。

1,layout.setGravity(Gravity.CENTER)和layoutParams.gravity = Gravity.CENTER;的区别;

       动态布局中,LinearLayout的使用比较多,其中控制控件方向主要通过这两个属性。两者的区别在于layout.setGravity(Gravity.CENTER)控制得是子控件相对于父控件的位置,配合layout.setOrientation(LinearLayout.VERTICAL或HORIZONTAL);的使用,来控制子控件的对齐关系。layoutParams.gravity = Gravity.CENTER;控制得是自身相对于父布局的一个位置,与父布局关联(如果父控件控制了子控件居中,那么孩子自己控制位置属性只能是在父亲前提之下控制自己的位置)。其实这两个属性就相当于静态布局中的android:gravity="center";和android:layout_gravity="center";

2,RelativeLayout控件的部分属性使用;

        RelativeLayout控制位置与LinearLayout不同,基本上主要有相对于整个布局的一些属性,例如居中于父布局,在父布局的左边等等之类的。这部分属性的使用RelativeLayout控件中需要使用relativeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);来控制。

3,布局技巧

      动态布局其实很不利于开发者开发,代码太过繁杂。而且如果需要动态更新界面并不想常规设置那么简单(比如用代码写一个圆,在不同情况下更换颜色),有些情况下是没办法直接更换背景的。这时候的处理方式就是 ,一开始就把不同颜色的布局加进来,而需要的时候需要控制好控件的隐藏和显示。不过这也会带来一些过度渲染的问题。也需要控制绘制的量。

4,Android低版本适配问题:(FrameLayout不能转化为AbsListView)

android—代码动态布局笔记

       发生这个情况的分析,可能是Google5.0以后的api会自动转化(没看过源码),在Android4.4.2以下版本中不会,需要主动将布局控件转为ABSListView。具体原因是这样的;Framelayout和AbsListView都是ViewGroup的子控件,处于同一等级。而GridView和ListView是AbsListView的子控件,等级小于FrameLayout,所以不可以直接转化。我的GridView添加的item因为继承的是FrameLayout,所以要把它转为AbsListView,如此才能够使用。

以上所有内容,就是我初次学习动态布局所接触的api和所碰到的问题。其实现在的大多数开发都不用到这总布局模式,这里也是给自己做个记录,仅供参考。首次写博客,有很多不足之处,请多多指教。