zoukankan      html  css  js  c++  java
  • android MeasureSpec的三个测量模式

    1.MeasureSpec含义

    其实可以去看MeasureSpec的文档,里面对MeasureSpec的作用介绍得很清楚.MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求。

    2.MeasureSpec的三个模式详解不定的,恰恰和AT_MOST

    视图大小的基本定义如下:
    MeasureSpec.EXACTLY - 视图应该是这么多像素,无论它实际上有多大。
    MeasureSpec.AT_MOST - 如果视图的尺寸较小,则视图可以是此尺寸或更小。
    MeasureSpec.UNSPECIFIED - 视图可以是它需要的任何大小,以显示它需要显示的内容。
    如果父视图的大小绑定,MeasureSpec.AT_MOST将应用于已设置为WRAP_CONTENT的视图。例如,您的父视图可能绑定到屏幕大小。它的孩子也会受到这种规模的束缚,但它可能不会那么大。因此,父视图将MeasureSpec设置为AT_MOST,告诉孩子它可以是0到屏幕大小之间的任何位置。孩子必须做出调整,以确保它符合所提供的范围。
    在特殊情况下,界限无关紧要。例如,ScrollView。对于ScrollView,子视图的高度无关紧要。因此,它将为孩子们提供一个未知的视图,告诉孩子他们可以达到他们需要的高度。ScrollView将处理它们的绘图和放置。

    翻译一下(直接用软件翻译过来的,不明白的话,下面会通过例子说明):

    查看的大小基本定义如下:
    MeasureSpec.EXACTLY - 表示父控件已经确切的指定了子查看的大小.MeasureSpec.AT_MOST
    - 表示子查看具体大小没有尺寸限制,但是存在上限,上限一般为父查看大小.MeasureSpec
    。未知 - 父控件没有给子视任何限制,子查看可以设置为任意大小。
    如果父视图的大小已经指定则MeasureSpec.AT_MOST将应用于已设置为WRAP_CONTENT的子视图。例如,你的父视图可能绑定到屏幕大小。它的孩子也会绑定到这个大小,但它可能不是那么大。因此,父视图将MeasureSpec设置为AT_MOST,它告诉孩子它可以在0和屏幕之间的任何地方。孩子必须进行调整,以确保它符合提供的界限。
    在特殊情况下,界限无关紧要。例如,一个ScrollView。在ScrollView的情况下,子视图的高度是不相关的。因此,它将向孩子提供一个未知视图,告诉孩子他们可以像他们需要的一样高 .ScrollView将处理它们的绘图和放置。

    模式数值描述
    UNSPECIFIED 0(0x00000000) 父控件没有给子视图任何限制,子视图可以设置为任意大小。
    究竟 1073741824(0x40000000) 表示父控件已经确切的指定了子视图的大小。
    最多 -2147483648(0x80000000) 表示子查看具体大小没有尺寸限制,但是存在上限,上限一般为父视图大小。

    3.例子解析

    这里分为两个部分例子,例子一是父布局是LinearLayout中,子布局是LinearLayout中,例子二是是父布局是滚动型,子布局是LinearLayout中。

    1)例子一解释EXACTLY和AT_MOST

    布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <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:orientation="vertical" >
    
            <com.example.transdotnavi.widget.NormalDot
                android:id="@+id/dot1"
                android:layout_width="20dp"
                android:layout_height="match_parent"
                android:background="#F7F6F5" >
            </com.example.transdotnavi.widget.NormalDot>
    
    </LinearLayout>
    

    子控件,对于具体解释可以看下面代码里的注释

    /**
     * @author Administrator
     * 2016-10-22
     * 
     * 普通的圆点导航器
     * 用于测试父控件是layout,子控件是layout的情况
     * 具体可以看layout.xml,里面定义了一个LinearLayout父布局,和一个NormalDot子布局
     * 测试机器:160dpi 480*800
     */
    public class NormalDot extends LinearLayout
    {
        public NormalDot(Context context)
        {
            super(context);
        }
        @SuppressLint("NewApi") 
        public NormalDot(Context context, AttributeSet attrs, int defStyle)
        {
            super(context, attrs, defStyle);
        }
        public NormalDot(Context context, AttributeSet attrs)
        {
            super(context, attrs);
        }
    
    //  MeasureSpec.AT_MOST = -2147483648 [0x80000000];  
    //  MeasureSpec.EXACTLY = 1073741824 [0x40000000];
    //  MeasureSpec.UNSPECIFIED = 0 [0x0];
        
    //  父布局LinearLayout固定width,height是match_parent(其实如果设置为wrap_content它的宽高也是等于屏幕宽高)
    //  情况一:
    //  当宽或高设为确定值时:即width=20dp,height=30dp,或者为match_parent。它会使用MeasureSpec.EXACTLY测量模式(表示父控件已经确切的指定了子View的大小)
    //  情况二:
    //  当宽或高设为wrap_content时,它会使用MeasureSpec.AT_MOST测量模式(表示子View具体大小没有尺寸限制,但是存在上限,上限一般为父View大小)
    //  情况三:
    //  MeasureSpec.UNSPECIFIED,一般是在特殊情况下出现,如在父布局是ScrollView中才会出现这种测量模式
    //  注意:
    //  父视图可能绑定到屏幕大小。 它的孩子也会绑定到这个大小,但它可能不是那么大。
    //  因此,父视图将MeasureSpec设置为AT_MOST ,
    //  它告诉孩子它可以在0和屏幕之间的任何地方。 孩子必须进行调整,以确保它符合提供的界限。
    //  通过一个例子解释上面面这句化的意思
    //  父布局宽高都设置为match_parent,这时候父布局大小就是屏幕大小,这时候,他的子视图设置为width=20dp,height=wrap_content
    //  看打出了的日志可以看到宽是20,高是800,这样的话我们应该能在屏幕的左边看到一条白色的宽为20的竖线,
    //  但是事实上,我们在界面是没有看到这条竖线的,这是因为子布局可以占据0到屏幕大小这个范围,但是子布局通过调整,将height设置为0了,所以
    //  我们看不到任何图像
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            int mode = MeasureSpec.getMode(widthMeasureSpec);
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int mode2 = MeasureSpec.getMode(heightMeasureSpec);
            int height = MeasureSpec.getSize(heightMeasureSpec);
            Log.i("lgy", "mode:"+mode+" "+width);
            Log.i("lgy", "mode2:"+mode2+" height:"+height);
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
    

    2)例子二解析的评论模式

    布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <com.example.transdotnavi.widget.LScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <com.example.transdotnavi.widget.NormalDot2
            android:id="@+id/dot2"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="#F7F6F5" >
    <!-- 
            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="TextView" />
                 -->
        </com.example.transdotnavi.widget.NormalDot2>
    
    </com.example.transdotnavi.widget.LScrollView>
    

    子控件

    /**
     * @author Administrator
     * 2016-10-22
     * 
     * 普通的圆点导航器
     * 用于测试父控件是ScrollView,子控件是layout的情况
     * 具体可以看layout2.xml,里面定义了一个ScrollView父布局,和一个NormalDot2子布局
     * 测试机器:160dpi 480*800
     */
    public class NormalDot2 extends LinearLayout
    {
    
        public NormalDot2(Context context)
        {
            super(context);
        }
    
        /**
         * @param context
         * @param attrs
         * @param defStyleAttr
         */
        @SuppressLint("NewApi") 
        public NormalDot2(Context context, AttributeSet attrs, int defStyleAttr)
        {
            super(context, attrs, defStyleAttr);
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @param context
         * @param attrs
         */
        public NormalDot2(Context context, AttributeSet attrs)
        {
            super(context, attrs);
            // TODO Auto-generated constructor stub
        }
    
    //  MeasureSpec.AT_MOST = -2147483648 [0x80000000];  
    //  MeasureSpec.EXACTLY = 1073741824 [0x40000000];
    //  MeasureSpec.UNSPECIFIED = 0 [0x0];
    
    //  这里主要展示的是MeasureSpec.UNSPECIFIED测量模式
    //  情况一:垂直的ScrollView
    //  父布局ScrollView宽高都是match_parent,子布局是一个NormalDot2设置宽高都是50dp
    //  从打出的日志可以看到,宽是以MeasureSpec.EXACTLY模式测量的,width=50,
    //  而高是以MeasureSpec.UNSPECIFIED模式测量的,height=0
    //  这时候如果NormalDot2布局里没有任何控件,那么就不会显示任何东西
    //  但如果在里面加个TextView,那么这个textView就会显示出来(当然这个textView是有内容的,否则也不会显示出来),
    //  但这时候height还是以MeasureSpec.UNSPECIFIED模式测量,height=0
        
    //  情况二:水平的ScrollView
    //  父布局HorizontalScrollView宽高都是match_parent,子布局是一个NormalDot2设置宽高都是50dp
    //  从打出的日志可以看到,宽是MeasureSpec.UNSPECIFIED模式测量的,width=0,
    //  而高是以MeasureSpec.EXACTLY模式测量的,height=50
    //  这时候如果NormalDot2布局里没有任何控件,那么就不会显示任何东西
    //  但如果在里面加个TextView,那么这个textView就会显示出来(当然这个textView是有内容的,否则也不会显示出来),
    //  但这时候width还是以MeasureSpec.UNSPECIFIED模式测量,width=0 
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            int mode = MeasureSpec.getMode(widthMeasureSpec);
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int mode2 = MeasureSpec.getMode(heightMeasureSpec);
            int height = MeasureSpec.getSize(heightMeasureSpec);
            Log.i("lgy", "============mode:"+mode+" "+width);
            Log.i("lgy", "=============mode2:"+mode2+" height:"+height);
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
    

    父控件(滚动型)

    /**
     * @author LGY
     * @time 2016-10-23
     * @action 
     */
    public class LScrollView extends 
    HorizontalScrollView
    //ScrollView
    {
    
        /**
         * @param context
         */
        public LScrollView(Context context)
        {
            super(context);
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @param context
         * @param attrs
         * @param defStyleAttr
         */
        public LScrollView(Context context, AttributeSet attrs, int defStyleAttr)
        {
            super(context, attrs, defStyleAttr);
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @param context
         * @param attrs
         */
        public LScrollView(Context context, AttributeSet attrs)
        {
            super(context, attrs);
            // TODO Auto-generated constructor stub
        }
        
        /* (non-Javadoc)
         * @see android.widget.ScrollView#onMeasure(int, int)
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            int mode = MeasureSpec.getMode(widthMeasureSpec);
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int mode2 = MeasureSpec.getMode(heightMeasureSpec);
            int height = MeasureSpec.getSize(heightMeasureSpec);
            Log.i("lgy", "ScrollViewmode:"+mode+" "+width);
            Log.i("lgy", "ScrollViewmode2:"+mode2+" height:"+height);
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }




  • 相关阅读:
    解决mac中wxpython对64位的支持
    python翻译词典实例
    php断点续传
    ubuntu配置telnet服务
    *p++,*++p,*(p++),*(++p)
    在main函数前后执行的函数之 C语言
    串行通讯协议--起止式异步通讯协议(UART)
    TTL电平, RS232电平以及CMOS电平的区别
    C 语言的关键字static 和C++ 的关键字static 有什么区别
    C语言各种数据类型取值范围
  • 原文地址:https://www.cnblogs.com/zquan/p/9623990.html
Copyright © 2011-2022 走看看