布局阶段

来源:互联网 时间:2017-01-13

这一阶段是对于布局的设置,因为对于一般的软件而言,当你点击进去某个activity时,往往这个activity与之前的activity有一些地方的显示
是相同的,比如,头部和尾部,那么这时为了减少工作量,我们可以使用include标签,对于include标签的使用,在这里提一下需要注意的地方,
如果你要在include标签中重新指定布局参数(android:layout_*属性),,就必须覆盖android:layout_height和android:layout_width。因为这
样才会生效,不然会提示错误。如果你是想指定过一个id,那么重新指定的id会覆盖原来的id。同时这里需要提一下很重要的一点,如果你想在
代码中为include标签重新指定内容,那么如果你直接通过id找到这个include标签,然后将view添加到这个标签中,这样是得不到的,可能就是
你通过id的确找到了这个标签,但是这个并不是真正的viewgroup,所以你无法将自己的view添加到上面,代码如下:


public void setActivityTitle(int RLayoutId,int account){ 
//找到include标签
LinearLayout linearLayout1= (LinearLayout) findViewById(R.id.include1);
//找到要附在include标签上的view
LinearLayout linearLayout= (LinearLayout) LayoutInflater.from(this).inflate(RLayoutId, null);
TextView textView= (TextView) linearLayout.findViewById(R.id.usertitlt_tv);
textView.setText(getString(R.string.useractivitytitle_name) + "(" + account + ")");
//附在include标签上
linearLayout1.addView(linearLayout);
}

这样是得不到的,那么我们应该怎么做呢?代码如下:


 public void setActivityTitle(int RLayoutId,int account){ 
//找到include标签
LinearLayout linearLayout1= (LinearLayout) findViewById(R.id.include1);
//将这个标签设置为不可见,注意这里设置为不可见,而不是GONE,因为如果是GONE就意味着这个include标签不存在,那么可能会影响整个布局
linearLayout1.setVisibility(View.INVISIBLE);
//找到这个include标签在的那个整个布局,之所以这里通过id来找,而不是通过inflate来生成,是因为生成之后你还需要再setcontextview()。
RelativeLayout relativeLayout= (RelativeLayout) findViewById(R.id.mainRelativeLayout);
LinearLayout linearLayout= (LinearLayout) LayoutInflater.from(this).inflate(RLayoutId, null);
TextView textView= (TextView) linearLayout.findViewById(R.id.usertitlt_tv);
textView.setText(getString(R.string.useractivitytitle_name) + "(" + account + ")");
//将要附加的view附加在整个布局上。
relativeLayout.addView(linearLayout);
}

这就是使用include标签需要注意的一些地方。
在这里也需要说一下布局的各个属性问题,由于篇幅问题,这里就提一个,就是layout_marginpadding的区别,layout_margin是控件在布局显
示的样子,padding则是控件的内容在控件中的位置,同时,Layout_grivatygrivaty这两者与之相似,layout_grivatylayout_margin对应,
grivatypadding对应,那么,layout_margn与layout_grivaty有什么区别呢?grivaty与padding又有什么区别呢?layout_grivaty与grivaty
的值都是给定的,我们只能在这些给定的属性中选择,而layout_margn与padding的值我们可以任意给,相对于layout_grivaty和grivaty更灵活,
我们根据需要选择合适的属性。
总之有layout的就是跟控件在布局中显示有关,没有的则是控制控件的内容的位置。


今天在设置布局时,因为我们想将所有的title去掉,那么如果我们去每一个activity中找,并且去掉,这样是非常不合理的,因此我们需要在
一个activity中管理一下,因此我定义了一个activityFrame继承了activity,这样我真正的activity都可以继承自定义的activity,这样管理
起来就很方便,那么我们可以requestWindowFeature(Window.FEATURE_NO_TITLE);来让它没有标题,同时因为我们需要动态的添加布局,我们可以这么办,步骤可以分为三步:
1.先找到我们需要插入的位置的布局,如我要插入到下面布局中的relativeLayout布局中


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.jdk.myaa.MainActivity">
<include layout="@layout/title_layout" android:id="@+id/include1"></include>
<include layout="@layout/buttom_layout" android:id="@+id/include2"></include>
<RelativeLayout
android:id="@+id/main_bodyRelativeLayout"
android:layout_below="@id/include1"
android:layout_above="@id/include2"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>
</RelativeLayout>

我们如何找到这个布局呢?通过代码: RelativeLayout relativeLayout= (RelativeLayout) findViewById(R.id.main_bodyRelativeLayout);
这样就找到了这个布局。
2.找到我们需要插入的布局,如我要插入如下布局:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
>
<GridView
android:id="@+id/gv"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="130dp"
android:horizontalSpacing="10dp"
android:verticalSpacing="100dp"
android:numColumns="3"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:listSelector="@drawable/myselector"
></GridView>
</LinearLayout>

这个如何寻找呢?通过下面代码:
ViewGroup v= (ViewGroup) LayoutInflater.from(this).inflate(R.layout.main_bodylayout, null);其中R.layout.main_bodylayout是上面
布局的名字。
3.将这个布局添加到对应的位置的布局中:
relativeLayout.addView(v);
这样就完成了动态添加,当然所添加的布局的属性会与你需要插入的布局属性相同,也就是跟第二步骤的布局相同,但是你也可以自己设置,设置的代码如下:


RelativeLayout.LayoutParams layoutParams=new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT);
relativeLayout.addView(v,layoutParams);

这样就行了。 上面是添加一个布局到对应位置中去,那么如何添加一个控件到对应的位置中去呢?
这个步骤与上述类似
1.与上面一致
2.找到我们需要插入的控件,比如我想插入这个布局中的GridView控件,如下:


 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
>
<GridView
android:id="@+id/gv"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="130dp"
android:horizontalSpacing="10dp"
android:verticalSpacing="100dp"
android:numColumns="3"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:listSelector="@drawable/myselector"
></GridView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="hahaha"/>
</LinearLayout>

那么我们该如何找到呢?代码如下:


ViewGroup v= (ViewGroup) LayoutInflater.from(this).inflate(LayoutId, null);
GridView g= (GridView) v.findViewById(R.id.gv);
v.removeView(g);

这里说一下第三行代码的作用,如果你没有这行代码,那么就会报错:
The specified child already has a parent. You must call removeView() on the child's parent first.
也就是说这个控件已经有一个parent了,我们要使用这个控件,就必须使用这个parent,如果你要强制使用这个
控件,那么你就需要让这个控件与这个parent脱离父子关系,也就是用这行代码,要理解这个,我们先理一下
activitywindowview的关系其实我们可以这么理解,假设activity是一个工人,他做了一个window,而这个
window需要玻璃,玻璃就是这个view,更准确是viewgroup,也就是根视图,然后我们需要打扮这个窗户,也就是
往窗户上贴窗花,假设我们的窗花是需要贴在纸上,然后让纸贴在玻璃上,因为这样我们以后要清除的时候,只要
把纸撕了就行,也就是说方便管理,然后这个窗花就是控件,纸就是view,也就是各种子视图,然后我们这里的情
况是要在这张纸上贴别的纸上的窗花,我们当然得把它撕下来先,也就是去掉父子关系,这就是第三行代码的作用
。不知道这么说你们是不是理解了呢?这里再加一些内容,其中的窗户实际上是phonewindow,而玻璃是viewgroup,
那么这个玻璃是怎么创建的呢?是通过activity方法中的attach()方法创建的,通过源代码你也可以看的到这是一个
phonewindow对象,那么什么时候调用的attach()方法呢?是在ActivityThreadperformLaunchActivity中调用了,
那么这里的纸是怎么创建的呢?是通过LayoutInflaterinflate()方法创建的,原料就是那些layout布局文件,而
这里的窗花就是控件,这个是在layout中写出来的或者用代码动态生成。将窗花贴在纸上是通过addview()方法,将
纸贴在玻璃上,是通过setcontentview()方法。那么玻璃(viewgroup)怎么生成的呢?实际上是通过installDecor();
方法得到的,这里的viewgroup更准确的说是DecorView,而installDecor();方法是生成DecorView,并且根据窗口属
性加载顶级视图布局、获取mContentParent、设置一些基本属性等。接下来还是放一张图片来说一下:



1


一、DecorView为整个Window界面的最顶层View。
二、DecorView只有一个子元素为LinearLayout。代表整个Window界面,包含通知栏,标题栏,内容显示栏三块区域。
三、LinearLayout里有两个FrameLayout子元素。
(20)为标题栏显示界面。只有一个TextView显示应用的名称。也可以自定义标题栏,载入后的自定义标题栏View将加入FrameLayout中。
(21)为内容栏显示界面。就是setContentView()方法载入的布局界面,加入其中。
这样是不是清晰点了。
3.与上面一样。
relativeLayout.addView(g);至于这里为什么事g而不是v应该理解吧。


这里还需要说一下,setcontentview()方法的作用,作用其实就是将纸贴在玻璃上,但是这里需要提一下:
activity 调用 setContentView() 时,Android 才会去绘制 layout 上的各个元素,并为其分配内存。
只有分配了内存以后,才能继续执行findViewById(); 才能得到引用,不然得到空引用。空引用意味着,
后面使用相应变量时就会发生访问的对象不存在的问题。当Activity重新setContentView()以后,那些之前
绘制的控件,内存都被灭掉了。这也就是说,你需要先setcontentview,然后再将布局动态添加上去。不然
就白费了。




相关阅读:
Top