简单来说:FrameLayout中的子元素总是以屏幕的左上角层叠在一起。

事实上,这是不确切的,我们可以对子元素添加android:layout_gravity属性来设置他们的位置的。



在FrameLayout布局里面android:layout_margin的各种属性必须依赖于android:layout_gravity,也就是说,要想margin生效,必须设定view的layout_gravity属性。单独设置marginLeft等属性是无效的。


先来看官方文档的定义:FrameLayout是最简单的一个布局对象。它被定制为你屏幕上的一个空白备用区域,之后你可以在其中填充一个单一对象 — 比如,一张你要发布的图片。所有的子元素将会固定在屏幕的左上角;你不能为FrameLayout中的一个子元素指定一个位置。后一个子元素将会直接在前一个子元素之上进行覆盖填充,把它们部份或全部挡住(除非后一个子元素是透明的)。


我的理解是,把FrameLayout当作画布canvas,固定从屏幕的左上角开始填充图片,文字等。看看示例,原来可以利用 android:layout_gravity来设置位置的




今天在学习实现墨迹天气那样的拖动效果时,看到用的是重写FrameLayout。翻了翻书,突然想明白,为什么用FrameLayout.


在FrameLayout中,用我看的书中的话说是,空间永远用不完。


复制代码



<?xml version="1.0" encoding="utf-8"?> 
 
 <FrameLayout 
 
 xmlns:android="http://schemas.android.com/apk/res/android" 
 
 android:layout_width="fill_parent" 
 
 android:layout_height="fill_parent" 
 
 android:background="#897753" 
 
 > 
 
 <ImageView 
 
 android:id="@+id/image1" 
 
 android:layout_width="fill_parent" 
 
 android:layout_height="fill_parent" 
 
 android:visibility="invisible" 
 
 android:src="@drawable/sky"/> 
 
 <ImageView 
 
 android:id="@+id/image2" 
 
 android:visibility="invisible" 
 
 android:layout_width="fill_parent" 
 
 android:layout_height="fill_parent" 
 
 android:src="@drawable/cloud"/> 
 
 <ImageView 
 
 android:id="@+id/image3" 
 
 android:visibility="invisible" 
 
 android:layout_width="fill_parent" 
 
 android:layout_height="fill_parent" 
 
 android:src="@drawable/sun"/> 
 
 </FrameLayout>



其中,image1、image2、image3都是在同一块空间的。可以说它们是重叠着的,界面显示的是最近用的那一个。


在我的代码中把它们都先不可见。


在整体代码中实现的是点一下屏幕就换一张图片。


另外,我个人感觉,实现拖动效果的关键原理就是framelayout使得几部分空间的重叠。设置只有一部分可见。当拖动时,设置其他部分移动。


发现下载附近要扣e币,我把代码也贴上,图片可以换成自己喜欢的~


FramLayoutTestActivity.java


复制代码



import java.util.ArrayList; 
 
 import java.util.List; 
 
 import android.app.Activity; 
 
 import android.os.Bundle; 
 
 import android.util.Log; 
 
 import android.view.MotionEvent; 
 
 import android.view.View; 
 
 import android.view.animation.Animation; 
 
 import android.widget.ImageView; 
 
 public class FramLayoutTestActivity extends Activity { 
 
 private String TAG = "FramLayoutTestActivity"; 
 
 private ImageView image1; 
 
 private ImageView image2; 
 
 private ImageView image3; 
 
 private List<ImageView> list; 
 
 private int count=0; 
 
 /** Called when the activity is first created. */ 
 
 @Override 
 
 public void onCreate(Bundle savedInstanceState) { 
 
 super.onCreate(savedInstanceState); 
 
 setContentView(R.layout.main); 
 
 image1=(ImageView)findViewById(R.id.image1); 
 
 image2=(ImageView)findViewById(R.id.image2); 
 
 image3=(ImageView)findViewById(R.id.image3); 
 
 list=new ArrayList<ImageView>(); 
 
 list.add(image1); 
 
 list.add(image2); 
 
 list.add(image3); 
 
 } 
 
 @Override 
 
 public boolean onTouchEvent(MotionEvent event) { 
 
 // TODO Auto-generated method stub 
 
 if(event.getAction()==MotionEvent.ACTION_DOWN) 
 
 { 
 
 Log.i(TAG,"move---"); 
 
 showImage(); 
 
 } 
 

 return super.onTouchEvent(event); 
 
 } 
 
 private void showImage() 
 
 { 
 
 image1.setVisibility(View.VISIBLE); 
 
 count=count%3; 
 
 for(ImageView i:list) 
 
 { 
 
 i.setVisibility(View.INVISIBLE); 
 
 } 
 
 list.get(count).setVisibility(View.VISIBLE); 
 
 count++; 
 
 } 
 
 } 
  

 main.xml


复制代码


<?xml version="1.0" encoding="utf-8"?> 
 
 <FrameLayout 
 
 xmlns:android="http://schemas.android.com/apk/res/android" 
 
 android:layout_width="fill_parent" 
 
 android:layout_height="fill_parent" 
 
 android:background="#897753" 
 
 > 
 
 <ImageView 
 
 android:id="@+id/image1" 
 
 android:layout_width="fill_parent" 
 
 android:layout_height="fill_parent" 
 
 android:visibility="invisible" 
 
 android:src="@drawable/sky"/> 
 
 <ImageView 
 
 android:id="@+id/image2" 
 
 android:visibility="invisible" 
 
 android:layout_width="fill_parent" 
 
 android:layout_height="fill_parent" 
 
 android:src="@drawable/cloud"/> 
 
 <ImageView 
 
 android:id="@+id/image3" 
 
 android:visibility="invisible" 
 
 android:layout_width="fill_parent" 
 
 android:layout_height="fill_parent" 
 
 android:src="@drawable/sun"/> 
 
 </FrameLayout>


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



FrameLayout



先来看官方文档的定义:FrameLayout是最简单的一个布局对象。它被定制为你屏幕上的一个空白备用区域,之后你可以在其中填充一个单一对象 — 比如,一张你要发布的图片。所有的子元素将会固定在屏幕的左上角;你不能为FrameLayout中的一个子元素指定一个位置。后一个子元素将会直接在前一个子元素之上进行覆盖填充,把它们部份或全部挡住(除非后一个子元素是透明的)。



我的理解是,把FrameLayout当作画布canvas,固定从屏幕的左上角开始填充图片,文字等。看看示例,原来可以利用 android:layout_gravity来设置位置的:



    1. <?xml version="1.0" encoding="utf-8"?>
    2. <FrameLayout
    3. xmlns:android="http://schemas.android.com/apk/res/android"
    4. android:layout_width="fill_parent"
    5. android:layout_height="fill_parent" >
    6. 
    7. <ImageView
    8. android:id="@+id/image"
    9. android:layout_width="fill_parent"
    10. android:layout_height="fill_parent"
    11. android:scaleType="center"
    12. android:src="@drawable/candle"
    13. />
    14. <TextView
    15. android:id="@+id/text1"
    16. android:layout_width="wrap_content"
    17. android:layout_height="wrap_content"
    18. android:layout_gravity="center"
    19. android:textColor="#00ff00"
    20. android:text="@string/hello"
    21. />
    22. <Button
    23. android:id="@+id/start"
    24. android:layout_width="wrap_content"
    25. android:layout_height="wrap_content"
    26. android:layout_gravity="bottom"
    27. android:text="Start"
    28. />
    29. </FrameLayout>



    效果图



    android FrameLayout 版本更新布局 framelayout布局属性_android

    android FrameLayout 版本更新布局 framelayout布局属性_xml_02

    android FrameLayout 版本更新布局 framelayout布局属性_android_03

    布局优化


    使用tools里面的hierarchyviewer.bat来查看layout的层次。在启动模拟器启动所要分析的程序,再启动hierarchyviewer.bat,选择模拟器以及该程序,点击“Load View Hierarchy”,就会开始分析。可以save as png。


    <merge> 减少视图层级结构


    从上图可以看到存在两个FrameLayout,红色框住的。如果能在layout文件中把FrameLayout声明去掉就可以进一步优化布局代码了。 但是由于布局代码需要外层容器容纳,如果


    直接删除FrameLayout则该文件就不是合法的布局文件。这种情况下就可以使用<merge> 标签了。


    修改为如下代码就可以消除多余的FrameLayout了:

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <merge  xmlns:android="http://schemas.android.com/apk/res/android">
    3. <ImageView
    4. android:id="@+id/image"
    5. android:layout_width="fill_parent"
    6. android:layout_height="fill_parent"
    7. android:scaleType="center"
    8. android:src="@drawable/candle"
    9. />
    10. <TextView
    11. android:id="@+id/text1"
    12. android:layout_width="wrap_content"
    13. android:layout_height="wrap_content"
    14. android:layout_gravity="center"
    15. android:textColor="#00ff00"
    16. android:text="@string/hello"
    17. />
    18. <Button
    19. android:id="@+id/start"
    20. android:layout_width="wrap_content"
    21. android:layout_height="wrap_content"
    22. android:layout_gravity="bottom"
    23. android:text="Start"
    24. />
    25. </merge>


    只能用于xml layout文件的根元素;在代码中使用LayoutInflater.Inflater()一个以merge为根元素的


    布局文件时候,需要使用 View inflate (int resource, ViewGroup root, boolean attachToRoot)指定一个ViewGroup 作为其容器,并且要设置attachToRoot 为true。


    <include> 重用layout代码


    如果在某个布局里面需要用到另一个相同的布局设计,可以通过<include> 标签来重用layout代码:


      1. <?xml version="1.0" encoding="utf-8"?>
      2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      3. android:orientation="vertical"
      4. android:layout_width="fill_parent"
      5. android:layout_height="fill_parent">
      6. 
      7. <include android:id="@+id/layout1" layout="@layout/relative" />
      8. <include android:id="@+id/layout2" layout="@layout/relative" />
      9. <include android:id="@+id/layout3" layout="@layout/relative" />
      10. 
      11. </LinearLayout>


      效果图


      android FrameLayout 版本更新布局 framelayout布局属性_xml_04


      "@layout/relative"不是引用Layout的id,而是引用res/layout/relative.xml,其内容是前面文章介绍RelativeLayout的布局代码。


      另外,通过<include>,除了可以覆写id属性值,还可以修改其他属性值,例如android:layout_width,android:height等。


      <viewstub> 延迟加载



      ViewStub 是一个不可见的,大小为0的View,最佳用途就是实现View的延迟加载,在需要的时候再加载View,可Java中常见的性能优化方法延迟加载一样。


      当调用ViewStub的setVisibility函数设置为可见或则调用 inflate初始化该View的时候,ViewStub引用的资源开始初始化,然后引用的资源替代ViewStub自己的位置填充在ViewStub的 位置。因此在没有调用setVisibility(int) 或则 inflate()函数之前 ViewStub一种存在组件树层级结构中,但是由于ViewStub非常轻量级,这对性能影响非常小。 可以通过ViewStub的inflatedId属性来重新定义引用的layout id。 例如:


      1. <ViewStub android:id="@+id/stub"
      2. android:inflatedId="@+id/subTree"
      3. android:layout="@layout/mySubTree"
      4. android:layout_width="120dip"
      5. android:layout_height="40dip" />


      上面定义的ViewStub ,可以通过id “stub”来找到,在初始化资源“mySubTree”后,stub从父组件中删除,然后"mySubTree"替代stub的位置。初始资源"mySubTree"得到的组件可以通过inflatedId 指定的id "subTree"引用。 然后初始化后的资源被填充到一个120dip宽、40dip高的地方。


      推荐使用下面的方式来初始化ViewStub:


      1. ViewStub stub = (ViewStub) findViewById(R.id.stub); 
      2. View inflated = stub.inflate();


      当调用inflate()函数的时候,ViewStub 被引用的资源替代,并且返回引用的view。 这样程序可以直接得到引用的view而不用再次调用函数 findViewById()来查找了。


      ViewStub目前有个缺陷就是还不支持 <merge /> 标签。


      layoutopt (Layout Optimization工具)


      这工具可以分析所提供的Layout,并提供优化意见。在tools文件夹里面可以找到layoutopt.bat。


      用法


      layoutopt <list of xml files or directories>


      参数


      一个或多个的Layout xml文件,以空格间隔;或者多个Layout xml文件所在的文件夹路径