精华内容
下载资源
问答
  • LayoutParams原理

    2016-08-18 11:13:37
    在上一篇文章里,我总结了一下自定义控件需要了解的基础知识:...其中,在View的测量流程里,View的测量宽高是由父控件的MeasureSpec和View自身的LayoutParams共同决定的。MeasureSpec是什么,上一篇文章里已经说

    http://www.2cto.com/kf/201606/514962.html

    在上一篇文章里,我总结了一下自定义控件需要了解的基础知识:View的绘制流程——《自定义控件知识储备-View的绘制流程》。其中,在View的测量流程里,View的测量宽高是由父控件的MeasureSpec和View自身的LayoutParams共同决定的。MeasureSpec是什么,上一篇文章里已经说得很清楚了(啥,没看过?快去路克路克,(??????)??)。而LayoutParams呢?是时候在这里做个了断了。

    LayoutParams是什么?

    LayoutParams,顾名思义,就是Layout Parameters :布局参数。
    很久很久以前,我就知道LayoutParams了,并且几乎天天见面。那时候在布局文件XML里,写的最多的肯定是android:layout_width = "match_parent"之类的了。比如:

     

    我们都知道layout_widthlayout_height这两个属性是为View指定宽度的。不过,当时年轻的我心里一直有个疑问:为什么要加上”layout_”前缀修饰呢?其它的描述属性,如textColorbackground,都很正常啊!讲道理,应该用widthheight描述宽高才对啊?

    后来呀,我遇到了LayoutParams,它说layout_width是它的属性而非View的,并且不只是针对这一个,而是所有以”layout_”开头的属性都与它有关!所以,它的东西当然要打上自己的标识”layout_”。(呵呵,嚣张个啥,到头来你自己还不是属于View的一部分( ̄┰ ̄*))

    既然layout_width这样的属性是LayoutParams定义的,那为何会出现在描述View的xml属性里呢?View和LayoutParams之间有什么恩怨纠缠呢?

    不吹不黑,咱们来看看官方文档是怎么说的:

    LayoutParams are used by views to tell their parents how they want to be laid out.
    – LayoutParams是View用来告诉它的父控件如何放置自己的。

    The base LayoutParams class just describes how big the view wants to be for both width and height.
    – 基类LayoutParams(也就是ViewGroup.LayoutParams)仅仅描述了这个View想要的宽度和高度。

    There are subclasses of LayoutParams for different subclasses of ViewGroup.
    – 不同ViewGroup的继承类对应着不同的ViewGroup.LayoutParams的子类。

    看着我妙到巅峰的翻译,想必大家都看懂了<( ̄▽ ̄)/。看不懂?那我再来画蛇添足稍微解释一下:

    上面我们提到过,描述View直接用它们自己的属性就好了,如textColorbackground等等,为什么还需要引入LayoutParams呢?在我看来,textColorbackground这样的属性都是只与TextView自身有关的,无论这个TextView处于什么环境,这些属性都是不变的。而layout_widthlayout_marginLeft这样的属性是与它的父控件息息相关的,是父控件通过LayoutParams提供这些”layout_”属性给孩子们用的;是父控件根据孩子们的要求(LayoutParams)来决定怎么测量,怎么安放孩子们的;是父控件……(写不下去了,我都快被父控件感动了,不得不再感慨一句,当父母的都不容易啊(′⌒`)) )。所以,View的LayoutParams离开了父控件,就没有意义了。

    基类LayoutParams是ViewGroup类里的一个静态内部类(看吧,这就证明了LayoutParams是与父控件直接相关的),它的功能很简单,只提供了widthheight两个属性,对应于xml里的layout_widthlayout_height。所以,对任意系统提供的容器控件或者是自定义的ViewGroup,其chid view总是能写layout_widthlayout_height属性的。

    自从有了ViewGroup.LayoutParams后,我们就可以在自定义ViewGroup时,根据自己的逻辑实现自己的LayoutParams,为孩子们提供更多的布局属性。不用说,系统里提供给我们的容器控件辣么多,肯定也有很多LayoutParams的子类啦。let us see see:

    ViewGroup.LayoutParams的截图

    果然,我们看到了很多ViewGroup.LayoutParams的子类,里面大部分我们应该都比较熟悉。如果你觉得和它们不熟,那就是你一厢情愿啦,你早就“偷偷摸摸”的用过它们好多次了→_→

    ViewGroup.MarginLayoutParams

    我们首先来看看ViewGroup.MarginLayoutParams,看名字我们也能猜到,它是用来提供margin属性滴。margin属性也是我们在布局时经常用到的。看看这个类里面的属性:

    public static class MarginLayoutParams extends ViewGroup.LayoutParams {
    
            public int leftMargin;
    
            public int topMargin;
    
            public int rightMargin;
    
            public int bottomMargin;
    
            private int startMargin = DEFAULT_MARGIN_RELATIVE;
    
            private int endMargin = DEFAULT_MARGIN_RELATIVE;
    
            ...
        }    

    前面4个属性是我们以前在布局文件里常用的,而后面的startMarginendMargin是为了支持RTL设计出来代替leftMarginrightMargin的。

    一般情况下,View开始部分就是左边,但是有的语言目前为止还是按照从右往左的顺序来书写的,例如阿拉伯语。在Android 4.2系统之后,Google在Android中引入了RTL布局,更好的支持了从右往左文字布局的显示。为了更好的兼容RTL布局,google推荐使用MarginStart和MarginEnd来替代MarginLeft和MarginRight,这样应用可以在正常的屏幕和从右往左显示文字的屏幕上都保持一致的用户体验。

    我们除了在布局文件里用layout_marginLeftlayout_marginTop这样的属性来指定单个方向的间距以外,还会用layout_margin来表示四个方向的统一间距。我们来通过源码看看这一过程:

     public MarginLayoutParams(Context c, AttributeSet attrs) {
                super();
    
                TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
                setBaseAttributes(a,
                        R.styleable.ViewGroup_MarginLayout_layout_width,
                        R.styleable.ViewGroup_MarginLayout_layout_height);
    
                int margin = a.getDimensionPixelSize(
                        com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
                if (margin >= 0) {
                    leftMargin = margin;
                    topMargin = margin;
                    rightMargin= margin;
                    bottomMargin = margin;
                } else {
                    leftMargin = a.getDimensionPixelSize(
                            R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
                            UNDEFINED_MARGIN);
                    if (leftMargin == UNDEFINED_MARGIN) {
                        mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
                        leftMargin = DEFAULT_MARGIN_RESOLVED;
                    }
                    ... 
                }
                ...
        }        
    

    在这个MarginLayoutParams的构造函数里,将获取到的xml布局文件里的属性转化成了leftMagrinrightMagrin等值。先获取xml里的layout_margin值,如果未设置,则再去获取layout_marginLeftlayout_marginRight等值。所以从这里可以得出一个小结论:

    在xml布局里,layout_margin属性的值会覆盖layout_marginLeftlayout_marginRight等属性的值。

    以前我还很傻很天真的猜测,属性写在后面,就会覆盖前面的属性。虽然经过实践,也能发现上述的结论,但是自己了解了背后的原理,再去看看源码实现,自然就有更深刻的印象了。<( ̄ˇ ̄)/

    揭开隐藏的LayoutParams

    在上文中提到,我们初学Android的时候经常在“偷偷摸摸”的使用着LayoutParams,而自己却还一脸懵逼。
    因为我们常用它的方式是在XML布局文件里,使用容器控件的LayoutParams里的各种属性来给孩子们布局。这种方式直观方便,直接就能在预览界面看到效果,但是同时布局也被我们写死了,无法动态改变。想要动态变化,那还是得不怕麻烦,使用代码来写。(实际上,我们写的XML布局最终也是通过代码来解析滴)

    好的,那还是让我们通过源码来揭开隐藏在ViewGroup里的LayoutParams吧!<( ̄︶ ̄)↗[GO!]……等会,我们该从哪里开始看源码呢?我认为有句名言说的在理:

    脱离场景谈源码,都是在耍流氓 ——英明神武蘑菇君

    上文提到,LayoutParams其实是父控件提供给child view的,好让child view选择如何测量和放置自己。所以肯定在child view添加到父控件的那一刻,child view就应该有LayoutParams了。我们来看看几个常见的添加View的方式:

    
    LinearLayout parent = (LinearLayout) findViewById(R.id.parent);
    // 1.直接添加一个“裸”的TextView,不主动指定LayoutParams
    TextView textView = new TextView(this);
    textView.setText("红色蘑菇君");
    textView.setTextColor(Color.RED);
    parent.addView(textView);
    
    // 2.先手动给TextView设定好LayoutParams,再添加
    textView = new TextView(this);
    textView.setText("绿色蘑菇君");
    textView.setTextColor(Color.GREEN);
    LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(300,300);
    textView.setLayoutParams(lp);
    parent.addView(textView);
    
    // 3.在添加的时候传递一个创建好的LayoutParams
    textView = new TextView(this);
    textView.setText("蓝色蘑菇君");
    textView.setTextColor(Color.BLUE);
    LinearLayout.LayoutParams lp2 = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,300);
    parent.addView(textView, lp2);
    

    上面代码展示的是3种往LinearLayout里动态添加TextView的方式,其中都涉及到了addView这个方法。我们来看看addView的几个重载方法:

    //这3个方法都来自于基类ViewGroup
    
     public void addView(View child) {
            addView(child, -1);
        }
    
     /*
      * @param child the child view to add
      * @param index the position at which to add the child    
      /
    public void addView(View child, int index) {
            if (child == null) {
                throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
            }
            LayoutParams params = child.getLayoutParams();
            if (params == null) {
                params = generateDefaultLayoutParams();
                if (params == null) {
                    throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
                }
            }
            addView(child, index, params);
        }
    
    public void addView(View child, LayoutParams params) {
            addView(child, -1, params);
        }    
    

    可以看出addView(View child)是调用了addView(View child, int index)方法的,在这个里面对child的LayoutParams做了判断,如果为null的话,则调用了generateDefaultLayoutParams方法为child生成一个默认的LayoutParams。这也合情合理,毕竟现在这个社会呀,像蘑菇君我这么懒的人太多,你要是不给个默认的选项,那别说友谊的小船了,就算泰坦尼克,那也说翻就翻!<( ̄︶ ̄)>……好的,那让我们看看LinearLayout为我们这群懒人生成了怎样的默认LayoutParams:

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
            if (mOrientation == HORIZONTAL) {
                return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            } else if (mOrientation == VERTICAL) {
                return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            }
            return null;
    }

    显然,LinearLayout是重写了基类ViewGroup里的generateDefaultLayoutParams方法的:如果布局是水平方向,则孩子们的宽高都是WRAP_CONTENT,而如果是垂直方向,高仍然是WRAP_CONTENT,但宽却变成了MATCH_PARENT。所以,这一点大家得注意,因为很有可能因为我们的懒,导致布局效果和我们理想中的不一样。因此呢,第1种添加View的方式是不推荐滴,像第2或第3种方式,添加的时候指定了LayoutParams,不仅明确,而且易修改。(果然还是勤劳致富呀…)

    上面三个重载的addView方法最终都调用了addView(View child, int index, LayoutParams params)这个参数最多的方法:

    public void addView(View child, int index, LayoutParams params) {
            ...
            requestLayout();
            invalidate(true);
            addViewInner(child, index, params, false);
        }
    
    private void addViewInner(View child, int index, LayoutParams params,
                boolean preventRequestLayout) {
            ...
    
            if (!checkLayoutParams(params)) {
                params = generateLayoutParams(params);
            }
    
            if (preventRequestLayout) {
                child.mLayoutParams = params;
            } else {
                child.setLayoutParams(params);
            }
    
            ...
        }    
    
    

    addView方法又调用了方法addViewInner,在这个私有方法里,又干了哪些偷偷摸摸的事呢?接着来看看:

    //这两个方法都重写了基类ViewGroup里的方法
    // Override to allow type-checking of LayoutParams.
    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
        return p instanceof LinearLayout.LayoutParams;
    }
    
    @Override
      protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        return new LayoutParams(p);
    }

    checkLayoutParams方法的作用是检查传递进来的LayoutParams是不是LinearLayout的LayoutParam。如果不是呢?再通过generateLayoutParams方法根据你传递的LayoutParams的属性构造一个LinearLayout的LayoutParams。不得不再次感慨父容器控件的不容易:我们懒得设置child view的LayoutParams,甚至是设置了错误的LayoutParams,父控件都在竭尽所能的纠正我们的错误,只为了给孩子提供一个舒适的环境。(╥╯^╰╥)

    不过呀,虽然父控件可以在添加View时帮我们纠正部分错误,但我们在其他情况下错误的修改child View的LayoutParams,那父控件也爱莫能助了。比如下面这种情况:

    LinearLayout parent = (LinearLayout) findViewById(R.id.parent);
    textView = new TextView(this);
    textView.setText("此处有BUG");
    LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(200,200);
    parent.addView(textView, lp);
    
    textView.setLayoutParams(new ViewGroup.LayoutParams(100,100));

    会直接报ClassCastException

    java.lang.ClassCastException: android.view.ViewGroup$LayoutParams cannot be cast to android.widget.LinearLayout$LayoutParams

    上面这种异常熟悉么?反正我是相当熟悉的〒▽〒……原因就是上面代码里的textView是LinearLayout的孩子,而我们调用textView的setLayoutParams方法强行给它设置了一个ViewGroup的LayoutParams,所有在LinearLayout重新进行绘制流程的时候,在onMeasure方法里,会进行强制类型转换操作:

    LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();

    所以App斯巴达了。也许你会说,我才不会这么傻,我知道textView的父控件是LinearLayout了,我肯定会给它设置相应的LayoutParams的!这是当然的啦,在这种明确的情况下,我们当然不会这么傻。但是,很不幸的是,有很多时候我们并不能一眼就看出来一个View的LayoutParams是什么类型的LayoutParams,这就需要动用你的智慧去分析分析啦,希望这篇文章能给你一些帮助。?(^?^●)?

    自定义LayoutParams

    在本文的开头就提到过:每个容器控件几乎都会有自己的LayoutParams实现,像LinearLayout、FrameLayout和RelativeLayout等等。所以,我们在自定义ViewGroup时,几乎都要自定义相应的LayoutParams。这一节呢,就是对如何自定义LayoutParams进行一个总结。

    我以一个简单的流布局FlowLayout为例,流布局的简单定义如下:

    FlowLayout:添加到此容器的控件自左往右依次排列,如果当前行的宽度不足以容纳下一个控件,就会将此控件放置到下一行。

    假设这个FlowLayout可以给它的孩子们提供一个gravity属性,效果就是让孩子能在某一行的垂直方向上选择三个位置:top(处于顶部)、center(居中)、bottom(处于底部)。咦?这个效果是不是和LinearLayout提供给孩子的layout_gravity属性很像?那好,我们来参考一下LinearLayout里的LayoutParams源码:

    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
    
            public float weight;
    
            public int gravity = -1;
    
            public LayoutParams(Context c, AttributeSet attrs) {
    
                super(c, attrs);
                TypedArray a =
                c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout);
                weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0);
                gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1);
    
                a.recycle();
            }
    
    
            public LayoutParams(ViewGroup.LayoutParams p) {
                super(p);
            }
    
    
            public LayoutParams(ViewGroup.MarginLayoutParams source) {
                super(source);
            }  
    
             public LayoutParams(LayoutParams source) {
                super(source);
    
                this.weight = source.weight;
                this.gravity = source.gravity;
            }
        }    
    

    首先,LinearLayout里的静态内部类LayoutParams是继承ViewGroup.MarginLayoutParams的,所以它的孩子们都可以用margin属性。事实上,绝大部分容器控件都是直接继承ViewGroup.MarginLayoutParams而非ViewGroup.LayoutParams。所以我们的FlowLayout也直接继承ViewGroup.MarginLayoutParams

    其次,LinearLayout支持两个属性weightgravity,这两个属性在xml对应的就是layout_weightlayout_gravity。在它的构造函数LayoutParams(Context c, AttributeSet attrs)里,将获取到的xml布局文件里的属性转化成了weightgravity的值。不过com.android.internal.R.styleable.LinearLayout_Layout这个东西是什么鬼?其实这是系统在xml属性文件里配置的declare-styleable,好让系统知道LinearLayout能为它的孩子们提供哪些属性支持。我们在布局的时候IDE也会给出这些快捷提示。而对于自定义的FlowLayout来说,模仿LinearLayout的写法,可以在attrs.xml文件里这么写:

    
            
        

    而剩下的几个构造方法起的作用就是从传递的LayoutParams参数里克隆属性了。

    依葫芦画瓢,FlowLayout的LayoutParams如下:

    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
    
            public int gravity = -1;
    
            public LayoutParams(Context c, AttributeSet attrs) {
    
                super(c, attrs);
                TypedArray a =
                c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout);
                weight = a.getFloat(R.styleable.FlowLayout_Layout, 0);
                gravity = a.getInt(R.styleable.FlowLayout_Layout_android_layout_gravity, -1);
    
                a.recycle();
            }
    
             public LayoutParams(ViewGroup.LayoutParams p) {
                super(p);
            }
    
    
            public LayoutParams(ViewGroup.MarginLayoutParams source) {
                super(source);
            }  
    
    
             public LayoutParams(LayoutParams source) {
                super(source);
                this.gravity = source.gravity;
            }
    
        }    

    看起来还是挺简单的吧?好,那我们这篇文章到此结束……等一等!好像忘记了点什么……
    如果对上面分析ViewGroup的addView方法的流程还有印象,可能你会注意ViewGroup里的这几个方法:

     public LayoutParams generateLayoutParams(AttributeSet attrs) {
            return new LayoutParams(getContext(), attrs);
        }
    
    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
            return p;
        }
    
    protected LayoutParams generateDefaultLayoutParams() {
            return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        }
    
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
            return  p != null;
        }

    为了能在添加child view时给它设置正确的LayoutParams,我们还需要重写上面几个方法(还问为啥要重写?快翻到前面再see see)。同样的,我们还是先来看看LinearLayout是怎么处理的吧:

     @Override
        public LayoutParams generateLayoutParams(AttributeSet attrs) {
            return new LinearLayout.LayoutParams(getContext(), attrs);
        }
    
    
        @Override
        protected LayoutParams generateDefaultLayoutParams() {
            if (mOrientation == HORIZONTAL) {
                return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            } else if (mOrientation == VERTICAL) {
                return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            }
            return null;
        }
    
        @Override
        protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
            return new LayoutParams(p);
        }
    
    
        // Override to allow type-checking of LayoutParams.
        @Override
        protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
            return p instanceof LinearLayout.LayoutParams;
        }

    那FlowLayout该如何重写上面的几个方法呢?相信聪明的你已经知道了。(??????)??

    总结

    这一篇文章从自定义控件的角度,并结合源码和表情包生动形象的谈了谈我所理解的LayoutParams。(生动,形象?真不要脸…(ˉ﹃ˉ))。不得不说,结合源码来学习某个知识点,的确是能起到事半功倍的作用。蘑菇君初来乍到,文章里如有错误和疏漏之处,欢迎指正和补充。

    预告

    下一篇文章打算记录一个简单的自定义ViewGroup:流布局FlowLayout的实现过程,将自定义控件知识储备-View的绘制流程里的知识点和本篇文章的LayoutParams结合起来。

    PS:写博客的初始阶段果然是有些艰辛,脑海里想写的很多,而真到了要以文字表达出来时,却有一种“爱你在心口难开”的尴尬。不过,感觉到艰难也就意味着自己在走上坡路,坚持下去,希望能给自己和大家带来更多的帮助。

    展开全文
  • LayoutParams原理

    2016-08-18 11:33:52
    LayoutParams原理

    LayoutParams原理图


    展开全文
  • LayoutParams详解 非常好的参考: https://www.jianshu.com/p/36b200a0bff4 动态布局: 如果想要代码动态写出上面的布局,就需要使用 LayoutParams 这个关键类了 LayoutParams 的作用是:子控件告诉父...


    LayoutParams详解

     

    非常好的参考:

    https://www.jianshu.com/p/36b200a0bff4

     

    动态布局:

        如果想要代码动态写出上面的布局,就需要使用 LayoutParams 这个关键类了

       LayoutParams 的作用是:子控件告诉父控件,自己要如何布局

     

    在添加到父布局时,设置 LayoutParams,通知父布局如何摆放自己

     

    <span style="color:#cccccc"><code class="language-java">ll.<span style="color:#f08d49">addView</span>(vt, layoutParams);<span style="color:#999999">// 在添加到父布局的时候</span></code></span>

     

     

     

     

    利用setLayoutParams方法对控件的layout进行布局更新

    <span style="color:#000000"><span style="color:#cccccc"><code class="language-css">textView.<span style="color:#f08d49">setLayoutParams</span>(textParams);</code></span></span>
    <span style="color:#000000"><span style="color:#cccccc"><code class="language-csharp">     <span style="color:#f8c555">RelativeLayout<span style="color:#cccccc">.</span>LayoutParams</span> <span style="color:#cc99cd">params</span> <span style="color:#67cdcc">=</span> <span style="color:#cc99cd">new</span> <span style="color:#f8c555">RelativeLayout<span style="color:#cccccc">.</span>LayoutParams</span>(mVgLp);
                    <span style="color:#cc99cd">params</span>.<span style="color:#f08d49">addRule</span>(RelativeLayout.ALIGN_PARENT_BOTTOM);
                    <span style="color:#cc99cd">params</span>.<span style="color:#f08d49">addRule</span>(RelativeLayout.ALIGN_PARENT_RIGHT);
                    mIv.<span style="color:#f08d49">setLayoutParams</span>(<span style="color:#cc99cd">params</span>);</code></span></span>
     
    我们发现,在对 LinearLayout 和 TextView 的 都不设置 LayoutParams 的情况下,
    LinearLayout 使用 MATCH_PARENT,而 TextView 使用 WRAP_CONTENT,至于为什么,我们要分析一下源码。



    ViewGroup里面的addview();

    所以测量由父类控制饿了

    public void addView(View child, int index) {
        if (child == null) {
            throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
        }
        LayoutParams params = child.getLayoutParams();
        if (params == null) {
            params = generateDefaultLayoutParams();
            if (params == null) {
                throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
            }
        }
        addView(child, index, params);
    }
    

     

     

    动态设置view的padding

     

    private void changesize(){
        if(weeklyRewardObtainTv.getText()!=null&&weeklyRewardObtainTv.getText().toString()!=null&&weeklyRewardObtainTv.getText().toString().length()>=10){
            int left=weeklyRewardObtainTv.getPaddingLeft();
            int top=weeklyRewardObtainTv.getPaddingTop();
            int bottom=weeklyRewardObtainTv.getPaddingBottom();
            int right=weeklyRewardObtainTv.getPaddingRight();
            weeklyRewardObtainTv.setPadding(DensityUtil.dip2px(ActivityWeeklyReward.this,53),top,right,bottom);
        }
    }
    

     

     

     

         虽然setContentView()方法大家都会用,但实际上Android界面显示的原理要比我们所看到的东西复杂得多。任何一个Activity中显示的界面其实主要都由两部分组成,标题栏和内容布局。标题栏就是在很多界面顶部显示的那部分内容,比如刚刚我们的那个例子当中就有标题栏,可以在代码中控制让它是否显示。而内容布局就是一个FrameLayout,这个布局的id叫作content,我们调用setContentView()方法时所传入的布局其实就是放到这个FrameLayout中的,这也是为什么这个方法名叫作setContentView(),而不是叫setView()。

    最后再附上一张Activity窗口的组成图吧,以便于大家更加直观地理解:

     

    LayoutInflater的基本用法有2种:

    1:LayoutInflater layoutInflater = LayoutInflater.from(context);

    2 :LayoutInflater layoutInflater = (LayoutInflater) context

    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    第一种方法是第二种的封装简写。

    得到了LayoutInflater的实例之后就可以调用它的inflate()方法来加载布局了,:layoutInflater.inflate(resourceId, root);

    那LayoutInflater 是如何工作的呢 ?

    LayoutInflater其实就是使用Android提供的pull解析方式来解析布局文件的。

     
    LayoutInflater实战用法举例:
    把一个自定义动态添加到一个布局里面
    1.自定义了一个view
    public class LayoutRunHealthCheck extends FrameLayout implements View.OnClickListener {
    
        
        private LinearLayout textViewClose;
        private HealthAnimationCircleProgressBar healthAnimationCircleProgressBar;
        private TextView tv_body_socre, tv_body_des, tv_body_detail, tv_start;
        private TextView tv_face_score;
    
        private SimpleDraweeView simpleDraweeView;
    
        private RelativeLayout layoutStart;
    
        private void buildView() {
            View view = LayoutInflater.from(context).inflate(R.layout.layout_run_health, null);
            textViewClose = view.findViewById(R.id.tv_close);
            tv_body_socre = view.findViewById(R.id.tv_body_socre);
            tv_body_des = view.findViewById(R.id.tv_body_des);
            tv_body_detail = view.findViewById(R.id.tv_body_detail);
            tv_start = view.findViewById(R.id.tv_start);
    
            layoutStart = view.findViewById(R.id.layout_start);
    
            simpleDraweeView = view.findViewById(R.id.body_feature);
    
            tv_face_score = view.findViewById(R.id.tv_face_score);
    
            healthAnimationCircleProgressBar = view.findViewById(R.id.cpb_face_score);
    
            textViewClose.setOnClickListener(this);
            layoutStart.setOnClickListener(this);
    
            view.setPadding(0, 0, 0, DensityUtil.dip2px(context, 0));
            this.addView(view);
    
            iniView();
            setData();
        }
    
    2.布局里面设置
    <LinearLayout
        android:id="@+id/frame_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"></LinearLayout>
    3.在代码里面动态添加:
    frameLayout = bottomView.findViewById(R.id.frame_layout);
    
    addHealthView();
    if (layoutRunHealthCheck == null && activity != null) {
        layoutRunHealthCheck = new LayoutRunHealthCheck(activity, type, healthListener);
        frameLayout.addView(layoutRunHealthCheck);
    
     
    LayoutInflater源码分析:
    public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
    
            final Context inflaterContext = mContext;
            final AttributeSet attrs = Xml.asAttributeSet(parser);
            Context lastContext = (Context) mConstructorArgs[0];
            mConstructorArgs[0] = inflaterContext;
            View result = root;
    
            try {
                // Look for the root node.
                int type;
                while ((type = parser.next()) != XmlPullParser.START_TAG &&
                        type != XmlPullParser.END_DOCUMENT) {
                    // Empty
                }
    
                if (type != XmlPullParser.START_TAG) {
                    throw new InflateException(parser.getPositionDescription()
                            + ": No start tag found!");
                }
    
                final String name = parser.getName();
    
                if (DEBUG) {
                    System.out.println("**************************");
                    System.out.println("Creating root view: "
                            + name);
                    System.out.println("**************************");
                }
    
                if (TAG_MERGE.equals(name)) {
                    if (root == null || !attachToRoot) {
                        throw new InflateException("<merge /> can be used only with a valid "
                                + "ViewGroup root and attachToRoot=true");
                    }
    
                    rInflate(parser, root, inflaterContext, attrs, false);
                } else {
                    // Temp is the root view that was found in the xml
                    final View temp = createViewFromTag(root, name, inflaterContext, attrs);
    
                    ViewGroup.LayoutParams params = null;
    
                    if (root != null) {
                        if (DEBUG) {
                            System.out.println("Creating params from root: " +
                                    root);
                        }
                        // Create layout params that match root, if supplied
                        params = root.generateLayoutParams(attrs);
                        if (!attachToRoot) {
                            // Set the layout params for temp if we are not
                            // attaching. (If we are, we use addView, below)
                            temp.setLayoutParams(params);
                        }
                    }
    
                    if (DEBUG) {
                        System.out.println("-----> start inflating children");
                    }
    
                    // Inflate all children under temp against its context.
                    rInflateChildren(parser, temp, attrs, true);
    
                    if (DEBUG) {
                        System.out.println("-----> done inflating children");
                    }
    
                    // We are supposed to attach all the views we found (int temp)
                    // to root. Do that now.
                    if (root != null && attachToRoot) {
                        root.addView(temp, params);
                    }
    
                    // Decide whether to return the root that was passed in or the
                    // top view found in xml.
                    if (root == null || !attachToRoot) {
                        result = temp;
                    }
                }
    
            } catch (XmlPullParserException e) {
                final InflateException ie = new InflateException(e.getMessage(), e);
                ie.setStackTrace(EMPTY_STACK_TRACE);
                throw ie;
            } catch (Exception e) {
                final InflateException ie = new InflateException(parser.getPositionDescription()
                        + ": " + e.getMessage(), e);
                ie.setStackTrace(EMPTY_STACK_TRACE);
                throw ie;
            } finally {
                // Don't retain static reference on context.
                mConstructorArgs[0] = lastContext;
                mConstructorArgs[1] = null;
    
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
    
            return result;
        }
    }
    发现merge,include标签,tag标签也在这个类里面
    public abstract class LayoutInflater {
    
        private static final String TAG = LayoutInflater.class.getSimpleName();
        private static final boolean DEBUG = false;
    
        /** Empty stack trace used to avoid log spam in re-throw exceptions. */
        private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
    
        /**
         * This field should be made private, so it is hidden from the SDK.
         * {@hide}
         */
        protected final Context mContext;
    
        // these are optional, set by the caller
        private boolean mFactorySet;
        private Factory mFactory;
        private Factory2 mFactory2;
        private Factory2 mPrivateFactory;
        private Filter mFilter;
    
        final Object[] mConstructorArgs = new Object[2];
    
        static final Class<?>[] mConstructorSignature = new Class[] {
                Context.class, AttributeSet.class};
    
        private static final HashMap<String, Constructor<? extends View>> sConstructorMap =
                new HashMap<String, Constructor<? extends View>>();
    
        private HashMap<String, Boolean> mFilterMap;
    
        private TypedValue mTempValue;
    
        private static final String TAG_MERGE = "merge";
        private static final String TAG_INCLUDE = "include";
        private static final String TAG_1995 = "blink";
        private static final String TAG_REQUEST_FOCUS = "requestFocus";
        private static final String TAG_TAG = "tag";
    1. 如果root为null,attachToRoot将失去作用,设置任何值都没有意义。
    2. 如果root不为null,attachToRoot设为true,则会给加载的布局文件的指定一个父布局,即root。
    3. 如果root不为null,attachToRoot设为false,则会将布局文件最外层的所有layout属性进行设置,当该view被添加到父view当中时,这些layout属性会自动生效。
    4. 在不设置attachToRoot参数的情况下,如果root不为null,attachToRoot参数默认为true。
     
    private View createViewFromTag(View parent, String name, Context context, AttributeSet attrs) {
        return createViewFromTag(parent, name, context, attrs, false);
    }
    问题:控件的大小怎么调试都没有用,外面少了一层父布局。首先View必须存在于一个布局中???、
     
     
     
    1.progrossbar的高度问题
    2.linearylayout的高度问题
     
     
    3.场景分析:通过一个viewPager自定义banner?     发现 viewPager wrap的高度不生效
     
    原理是:viewPager重写了onMesure。固定了自己的高度。然后测量了子view
     
    viewpager本来是用来切换整个屏幕的。不是用来做banner的。
    所以高度要自己测量高度。
     
    测量原理:树的深度变量。
     
     
    解决办法:重写onMesure方法
    先度量子view然后再度量自己。
     
    这样是不正确的,要用到LayoutParams才行
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
        int height = 0;
        for(int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            int h = child.getMeasuredHeight();
            if(h > height) height = h;
        }
    
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
    
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     
    一个viewGroup。父类给他一个参考值,同时要先度量子view。才能确定
    有点像view的时间分发。
    通过源码发现:测量自己之前先测量自己都子view
     
    ViewPager源码:
    setMeasuredDimension:测量自己
    LayoutParams:子空间的参数测量
    MeasureSpec.makeMeasureSpec(widthSize, widthMode);  测量的计算模式
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // For simple implementation, our internal size is always 0.
        // We depend on the container to specify the layout size of
        // our view.  We can't really know what it is since we will be
        // adding and removing different arbitrary views and do not
        // want the layout to change as this happens.
        setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),
                getDefaultSize(0, heightMeasureSpec));
    
        final int measuredWidth = getMeasuredWidth();
        final int maxGutterSize = measuredWidth / 10;
        mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize);
    
        // Children are just made to fill our space.
        int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight();
        int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
    
        /*
         * Make sure all children have been properly measured. Decor views first.
         * Right now we cheat and make this less complicated by assuming decor
         * views won't intersect. We will pin to edges based on gravity.
         */
        int size = getChildCount();
        for (int i = 0; i < size; ++i) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                if (lp != null && lp.isDecor) {
                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
                    int widthMode = MeasureSpec.AT_MOST;
                    int heightMode = MeasureSpec.AT_MOST;
                    boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM;
                    boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT;
    
                    if (consumeVertical) {
                        widthMode = MeasureSpec.EXACTLY;
                    } else if (consumeHorizontal) {
                        heightMode = MeasureSpec.EXACTLY;
                    }
    
                    int widthSize = childWidthSize;
                    int heightSize = childHeightSize;
                    if (lp.width != LayoutParams.WRAP_CONTENT) {
                        widthMode = MeasureSpec.EXACTLY;
                        if (lp.width != LayoutParams.MATCH_PARENT) {
                            widthSize = lp.width;
                        }
                    }
                    if (lp.height != LayoutParams.WRAP_CONTENT) {
                        heightMode = MeasureSpec.EXACTLY;
                        if (lp.height != LayoutParams.MATCH_PARENT) {
                            heightSize = lp.height;
                        }
                    }
                    final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
                    final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
                    child.measure(widthSpec, heightSpec);
     MeasureSpec.makeMeasureSpec(widthSize, widthMode);
     
    makeMeasuerMespect:度量计算:把参数转成具体指
    LayoutParams      也经常用到。
                  
    :度量计算:把参数转成具体指
    LayoutParams ====== ====转为100dp
     
     
     
    fragment 里面的getactivity==null的原因。
    比如:推送的时候,点击通知栏。因为他们不在同一个进程
     
    LayoutInflate使用:setcontentview。
    第二个:adapter里面使用
     
    LayoutInflate的调用原理:
    里面如何解析including和其他3种方式
     
    LayoutInflate相关的地方
    有的时候高度无效,和根布局有关系。多添加一层view,设置宽高就可以额。
     
     
    onmesure什么时候触发:
    1.父类调用一次
    2.onlayout的时候又去调用次
     
    4.类似的情况,recyleView里面的item高度问题。同样可以
     
     
    看源码工具:source insight
     
     
    参考博客:
     
    360悬浮球实现  
     


     

    展开全文
  • WindowManager.LayoutParams 是 WindowManager 接口的嵌套类;继承于 ViewGroup.LayoutParams 。 它的内容十分丰富。其实WindowManager.java的主要内容就是由这个类定义构成。下面来分析一下这个类: 定义 public ...

    WindowManager.LayoutParams 是 WindowManager 接口的嵌套类;继承于 ViewGroup.LayoutParams 。
    它的内容十分丰富。其实WindowManager.java的主要内容就是由这个类定义构成。下面来分析一下这个类:

    定义

    public static class WindowManager.LayoutParams
    extends ViewGroup.LayoutParams implements Parcelable

    继承关系

    java.lang.Object
    android.view.ViewGroup.LayoutParams
    ↳android.view.WindowManager.LayoutParams

    继承来的属性与常量

    从 ViewManager.LayoutParams 继承来的属性:
    android:layout_height Specifies the basic height of the view.
    android:layout_width Specifies the basic width of the view.

    从 ViewManager.LayoutParams继承的常量:
    FILL_PARENT

     WRAP_CONTENT
    
     MATCH_PARENT
    
    

    两个变量:widthheight
    属性及可用的常量定义
    1. public int x;
    如果忽略gravity属性,那么它表示窗口的绝对X位置。 什么是gravity属性呢?简单地说,就是窗口如何停靠。 当设置了 Gravity.LEFT
    或 Gravity.RIGHT
    之后,x值就表示到特定边的距离。
    2. public inty;
    如果忽略gravity属性,那么它表示窗口的绝对Y位置。 当设置了 Gravity.TOP
    或 Gravity.BOTTOM
    之后,y值就表示到特定边的距离。
    3. public float
    horizontalWeight
    ; public float
    verticalWeight
    ;
    在纵/横向上,为关联的view预留了多少扩展空间(像素)。如果是0,那么此view不能被拉伸。 其他情况下,扩展空间(像素)将被widget所均分。
    4. public
    int
    type
    ;
    窗口类型。有3种主要类型:Applicationwindows:
    取值在 FIRST_APPLICATION_WINDOW
    和 LAST_APPLICATION_WINDOW
    之间。 是通常的、顶层的应用程序窗口。必须将 token 设置成 activity 的 token 。Sub_windows:
    取值在 FIRST_SUB_WINDOW
    和 LAST_SUB_WINDOW
    之间。 与顶层窗口相关联,token 必须设置为它所附着的宿主窗口的 token。Systemwindows:
    取值在 FIRST_SYSTEM_WINDOW
    和 LAST_SYSTEM_WINDOW
    之间。 用于特定的系统功能。它不能用于应用程序,使用时需要特殊权限。

    下面定义了 type
    的取值:

      应用程序窗口。
      public static final int
    
    

    FIRST_APPLICATION_WINDOW
    = 1;

      所有程序窗口的“基地”窗口,其他应用程序窗口都显示在它上面。     
      public static final int
    
    

    TYPE_BASE_APPLICATION
    =1;

      普通应哟功能程序窗口。token必须设置为Activity的token,以指出该窗口属谁。      public static final int
    
    

    TYPE_APPLICATION
    = 2;
    用于应用程序启动时所显示的窗口。应用本身不要使用这种类型。 它用于让系统显示些信息,直到应用程序可以开启自己的窗口。 public static final int
    TYPE_APPLICATION_STARTING
    = 3; 应用程序窗口结束。 public static final int
    LAST_APPLICATION_WINDOW
    = 99;
    子窗口。子窗口的Z序和坐标空间都依赖于他们的宿主窗口。
    public static final int
    FIRST_SUB_WINDOW
    = 1000;
    面板窗口,显示于宿主窗口上层。
    public static final int
    TYPE_APPLICATION_PANEL
    = FIRST_SUB_WINDOW
    ;
    媒体窗口,例如视频。显示于宿主窗口下层。
    public static final int
    TYPE_APPLICATION_MEDIA
    = FIRST_SUB_WINDOW
    +1;
    应用程序窗口的子面板。显示于所有面板窗口的上层。(GUI的一般规律,越“子”越靠上)
    public static final int
    TYPE_APPLICATION_SUB_PANEL
    = FIRST_SUB_WINDOW
    +2;
    对话框。类似于面板窗口,绘制类似于顶层窗口,而不是宿主的子窗口。
    public static final int
    TYPE_APPLICATION_ATTACHED_DIALOG
    = FIRST_SUB_WINDOW
    +3;
    媒体信息。显示在媒体层和程序窗口之间,需要实现透明(半透明)效果。(例如显示字幕)
    public static final int
    TYPE_APPLICATION_MEDIA_OVERLAY
    = FIRST_SUB_WINDOW
    +4;
    子窗口结束。( End of types of sub-windows )
    public static final int
    LAST_SUB_WINDOW
    = 1999;
    系统窗口。非应用程序创建。
    public static final int
    FIRST_SYSTEM_WINDOW
    = 2000;
    状态栏。只能有一个状态栏;它位于屏幕顶端,其他窗口都位于它下方。
    public static final int
    TYPE_STATUS_BAR
    = FIRST_SYSTEM_WINDOW
    ;
    搜索栏。只能有一个搜索栏;它位于屏幕上方。
    public static final int
    TYPE_SEARCH_BAR
    = FIRST_SYSTEM_WINDOW
    +1;
    电话窗口。它用于电话交互(特别是呼入)。它置于所有应用程序之上,状态栏之下。
    public static final int
    TYPE_PHONE
    = FIRST_SYSTEM_WINDOW
    +2;
    系统提示。它总是出现在应用程序窗口之上。
    public static final int
    TYPE_SYSTEM_ALERT
    = FIRST_SYSTEM_WINDOW
    +3;
    锁屏窗口。
    public static final int
    TYPE_KEYGUARD
    = FIRST_SYSTEM_WINDOW
    +4;
    信息窗口。用于显示toast。
    public static final int
    TYPE_TOAST
    = FIRST_SYSTEM_WINDOW
    +5;
    系统顶层窗口。显示在其他一切内容之上。此窗口不能获得输入焦点,否则影响锁屏。
    public static final int
    TYPE_SYSTEM_OVERLAY
    = FIRST_SYSTEM_WINDOW
    +6;
    电话优先,当锁屏时显示。此窗口不能获得输入焦点,否则影响锁屏。
    public static final int
    TYPE_PRIORITY_PHONE
    = FIRST_SYSTEM_WINDOW
    +7;
    系统对话框。(例如音量调节框)。
    public static final int
    TYPE_SYSTEM_DIALOG
    = FIRST_SYSTEM_WINDOW
    +8;
    锁屏时显示的对话框。
    public static final int
    TYPE_KEYGUARD_DIALOG
    = FIRST_SYSTEM_WINDOW
    +9;
    系统内部错误提示,显示于所有内容之上。
    public static final int
    TYPE_SYSTEM_ERROR
    = FIRST_SYSTEM_WINDOW
    +10;
    内部输入法窗口,显示于普通UI之上。应用程序可重新布局以免被此窗口覆盖。
    public static final int
    TYPE_INPUT_METHOD
    = FIRST_SYSTEM_WINDOW
    +11;
    内部输入法对话框,显示于当前输入法窗口之上。
    public static final int
    TYPE_INPUT_METHOD_DIALOG
    = FIRST_SYSTEM_WINDOW
    +12;
    墙纸窗口。
    public static final int
    TYPE_WALLPAPER
    = FIRST_SYSTEM_WINDOW
    +13;
    状态栏的滑动面板。
    public static final int
    TYPE_STATUS_BAR_PANEL
    = FIRST_SYSTEM_WINDOW
    +14;
    系统窗口结束。
    public static final int
    LAST_SYSTEM_WINDOW
    = 2999;
    5. public int
    memoryType
    ;
    指出窗口所使用的内存缓冲类型。默认为 NORMAL

    **下面定义了 memoryType

    的取值:**
    窗口缓冲位于主内存。
    public static final int
    MEMORY_TYPE_NORMAL
    = 0;
    窗口缓冲位于可以被DMA访问,或者硬件加速的内存区域。
    public static final int
    MEMORY_TYPE_HARDWARE
    = 1;
    窗口缓冲位于可被图形加速器访问的区域。
    public static final int
    MEMORY_TYPE_GPU
    = 2;
    窗口缓冲不拥有自己的缓冲区,不能被锁定。缓冲区由本地方法提供。
    public static final int
    MEMORY_TYPE_PUSH_BUFFERS
    = 3;
    6. public int
    flags
    ; 行为选项/旗标,默认为 none .

    下面定义了 flags
    的取值:

      窗口之后的内容变暗。     
    
    

    public static final int
    FLAG_DIM_BEHIND
    = 0x00000002;
    窗口之后的内容变模糊。
    public static final int
    FLAG_BLUR_BEHIND
    = 0x00000004;

      不许获得焦点。      不能获得按键输入焦点,所以不能向它发送按键或按钮事件。那些时间将发送给它后面的可以获得焦点的窗口。此选项还会设置FLAG_NOT_TOUCH_MODAL选项。设置此选项,意味着窗口不能与软输入法进行交互,所以它的Z序独立于任何活动的输入法(换句话说,它可以全屏显示,如果需要的话,可覆盖输入法窗口)。要修改这一行为,可参考FLAG_ALT_FOCUSALBE_IM选项。     
    
    

    public static final int
    FLAG_NOT_FOCUSABLE
    = 0x00000008;
    不接受触摸屏事件。
    public static final int
    FLAG_NOT_TOUCHABLE
    = 0x00000010;
    当窗口可以获得焦点(没有设置 FLAG_NOT_FOCUSALBE
    选项)时,仍然将窗口范围之外的点设备事件(鼠标、触摸屏)发送给后面的窗口处理。否则它将独占所有的点设备事件,而不管它们是不是发生在窗口范围内。
    public static final int
    FLAG_NOT_TOUCH_MODAL
    = 0x00000020;
    如果设置了这个标志,当设备休眠时,点击触摸屏,设备将收到这个第一触摸事件。 通常第一触摸事件被系统所消耗,用户不会看到他们点击屏幕有什么反应。
    public static final int
    FLAG_TOUCHABLE_WHEN_WAKING
    = 0x00000040;
    当此窗口为用户可见时,保持设备常开,并保持亮度不变。
    public static final int
    FLAG_KEEP_SCREEN_ON
    = 0x00000080;
    窗口占满整个屏幕,忽略周围的装饰边框(例如状态栏)。此窗口需考虑到装饰边框的内容。
    public static final int
    FLAG_LAYOUT_IN_SCREEN
    =0x00000100;
    允许窗口扩展到屏幕之外。
    public static final int
    FLAG_LAYOUT_NO_LIMITS
    =0x00000200;
    窗口显示时,隐藏所有的屏幕装饰(例如状态条)。使窗口占用整个显示区域。
    public static final int
    FLAG_FULLSCREEN
    = 0x00000400;
    此选项将覆盖FLAG_FULLSCREEN选项,并强制屏幕装饰(如状态条)弹出。
    public static final int
    FLAG_FORCE_NOT_FULLSCREEN
    =0x00000800;
    抖动。指 对半透明的显示方法。又称“点透”。图形处理较差的设备往往用“点透”替代Alpha混合。
    public static final int
    FLAG_DITHER
    = 0x00001000;
    不允许屏幕截图。
    public static final int
    FLAG_SECURE
    = 0x00002000;
    一种特殊模式,布局参数用于指示显示比例。
    public static final int
    FLAG_SCALED
    = 0x00004000;
    当屏幕有可能贴着脸时,这一选项可防止面颊对屏幕造成误操作。
    public static final int
    FLAG_IGNORE_CHEEK_PRESSES
    = 0x00008000;
    当请求布局时,你的窗口可能出现在状态栏的上面或下面,从而造成遮挡。当设置这一选项后,窗口管理器将确保窗口内容不会被装饰条(状态栏)盖住。
    public static final int
    FLAG_LAYOUT_INSET_DECOR
    = 0x00010000;
    反转FLAG_NOT_FOCUSABLE选项。 如果同时设置了FLAG_NOT_FOCUSABLE选项和本选项,窗口将能够与输入法交互,允许输入法窗口覆盖; 如果FLAG_NOT_FOCUSABLE没有设置而设置了本选项,窗口不能与输入法交互,可以覆盖输入法窗口。
    public static final int
    FLAG_ALT_FOCUSABLE_IM
    = 0x00020000;
    如果你设置了FLAG_NOT_TOUCH_MODAL,那么当触屏事件发生在窗口之外事,可以通过设置此标志接收到一个MotionEvent.ACTION_OUTSIDE事件。注意,你不会收到完整的down/move/up事件,只有第一次down事件时可以收到ACTION_OUTSIDE。
    public static final int
    FLAG_WATCH_OUTSIDE_TOUCH
    = 0x00040000;
    当屏幕锁定时,窗口可以被看到。这使得应用程序窗口优先于锁屏界面。可配合FLAG_KEEP_SCREEN_ON选项点亮屏幕并直接显示在锁屏界面之前。可使用FLAG_DISMISS_KEYGUARD选项直接解除非加锁的锁屏状态。此选项只用于最顶层的全屏幕窗口。
    public static final int
    FLAG_SHOW_WHEN_LOCKED
    = 0x00080000;
    请求系统墙纸显示在你的窗口后面。窗口必须是半透明的。
    public static final int
    FLAG_SHOW_WALLPAPER
    = 0x00100000;
    窗口一旦显示出来,系统将点亮屏幕,正如用户唤醒设备那样。
    public static final int
    FLAG_TURN_SCREEN_ON
    = 0x00200000;
    解除锁屏。只有锁屏界面不是加密的才能解锁。如果锁屏界面是加密的,那么用户解锁之后才能看到此窗口,除非设置了FLAG_SHOW_WHEN_LOCKED选项。
    public static final int
    FLAG_DISMISS_KEYGUARD
    = 0x00400000;
    锁屏界面淡出时,继续运行它的动画。
    public static final int
    FLAG_KEEP_SURFACE_WHILE_ANIMATING
    =0x10000000;
    以原始尺寸显示窗口。用于在兼容模式下运行程序。
    public static final int
    FLAG_COMPATIBLE_WINDOW
    = 0x20000000;
    用于系统对话框。设置此选项的窗口将无条件获得焦点。
    public static final int
    FLAG_SYSTEM_ERROR
    = 0x40000000;
    7. public int
    softInputMode
    ; 软输入法模式选项:
    以下选项与 softInputMode
    有关:

    软输入区域是否可见。
    public static final int
    SOFT_INPUT_MASK_STATE
    = 0x0f;
    未指定状态。
    public static final int
    SOFT_INPUT_STATE_UNSPECIFIED
    = 0;
    不要修改软输入法区域的状态。
    public static final int
    SOFT_INPUT_STATE_UNCHANGED
    = 1;
    隐藏输入法区域(当用户进入窗口时)。
    public static final int
    SOFT_INPUT_STATE_HIDDEN
    = 2;
    当窗口获得焦点时,隐藏输入法区域。
    public static final int
    SOFT_INPUT_STATE_ALWAYS_HIDDEN
    = 3;
    显示输入法区域(当用户进入窗口时)。
    public static final int
    SOFT_INPUT_STATE_VISIBLE
    = 4;
    当窗口获得焦点时,显示输入法区域。
    public static final int
    SOFT_INPUT_STATE_ALWAYS_VISIBLE
    = 5;
    窗口应当主动调整,以适应软输入窗口。
    public static final int
    SOFT_INPUT_MASK_ADJUST
    = 0xf0;
    未指定状态,系统将根据窗口内容尝试选择一个输入法样式。
    public static final int
    SOFT_INPUT_ADJUST_UNSPECIFIED
    = 0x00;
    当输入法显示时,允许窗口重新计算尺寸,使内容不被输入法所覆盖。 不可与SOFT_INPUT_ADJUSP_PAN混合使用,如果两个都没有设置,系统将根据窗口内容自动设置一个选项。
    public static final int
    SOFT_INPUT_ADJUST_RESIZE
    = 0x10;
    输入法显示时平移窗口。它不需要处理尺寸变化,框架能够移动窗口以确保输入焦点可见。 不可与SOFT_INPUT_ADJUST_RESIZE混合使用;如果两个都没设置,系统将根据窗口内容自动设置一个选项。
    public static final int
    SOFT_INPUT_ADJUST_PAN
    = 0x20;
    当用户转至此窗口时,由系统自动设置,所以你不要设置它。 当窗口显示之后该标志自动清除。
    public static final int
    SOFT_INPUT_IS_FORWARD_NAVIGATION
    = 0x100;

    8. public int
    gravity
    ; gravity 属性。什么是gravity属性呢?简单地说,就是窗口如何停靠。
    9. public float
    horizontalMargin
    ; 水平边距,容器与widget之间的距离,占容器宽度的百分率。
    10. public float
    verticalMargin
    ; 纵向边距。
    11. public int
    format
    ;期望的位图格式。默认为不透明。参考android.graphics.PixelFormat。

    12. public int
    windowAnimations
    ;窗口所使用的动画设置。它必须是一个系统资源而不是应用程序资源,因为窗口管理器不能访问应用程序。
    13. public float
    alpha
    = 1.0f;整个窗口的半透明值,1.0表示不透明,0.0表示全透明。
    14. public float
    dimAmount
    = 1.0f;当FLAG_DIM_BEHIND设置后生效。该变量指示后面的窗口变暗的程度。1.0表示完全不透明,0.0表示没有变暗。
    15. public float
    screenBrightness
    = -1.0f;用来覆盖用户设置的屏幕亮度。表示应用用户设置的屏幕亮度。从0到1调整亮度从暗到最亮发生变化。

    16. public
    IBinder token
    = null;窗口的标示符。( Identifier for this window. This will usually be filled in for you. )
    17. public String
    packageName
    = null;此窗口所在的包名。
    18. public int
    screenOrientation
    =ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
    ;
    屏幕方向,参见android.content.pm.ActivityInfo#screenOrientation。

    19. 在兼容模式下,备份/恢复参数所使用的内部缓冲区。publicint[] mCompatibilityParamsBackup
    = null;

    **常用方法
    **
    1. public final int copyFrom (WindowManager.LayoutParams o);

    下面定义了各种“CHANGE”信息,为copyFrom函数所使用。public staticfinal int LAYOUT_CHANGED =1<<0;
    public staticfinal int TYPE_CHANGED =1<<1;
    public staticfinal int FLAGS_CHANGED =1<<2;
    public staticfinal int FORMAT_CHANGED =1<<3;
    public staticfinal int ANIMATION_CHANGED =1<<4;
    public staticfinal int DIM_AMOUNT_CHANGED =1<<5;
    public staticfinal int TITLE_CHANGED =1<<6;
    public staticfinal int ALPHA_CHANGED =1<<7;
    public staticfinal int MEMORY_TYPE_CHANGED =1<<8;
    public staticfinal int SOFT_INPUT_MODE_CHANGED =1<<9;
    public staticfinal int SCREEN_ORIENTATION_CHANGED =1<<10;
    public staticfinal int SCREEN_BRIGHTNESS_CHANGED =1<<11;

    展开全文
  • 主要介绍一下View的工作原理,还有自定义View的实现方法,在Android知识体系中,View是一个很重要的角色,简单来说,View是Android中视觉的呈现。在界面上Android提供了一套完整的GUI库,里面有很多控件,但是有时候...
  • LayoutParams封装的是View向父容器传达自己意愿的信息,它封装了Layout的位置、高、宽等信息,表达自己想变成一个什么尺寸的View。 使用示例: SwipeRefreshLayout refreshLayout = new NsRefreshLayout...
  • 改变LayoutParam是什么原理? LayoutParam的基类是ViewGroup.LayoutParams,只有宽高两个属性 常用的直接子类只有一个 MarginLayoutParams,他也是ViewGroup的静态内部类,多出了margin的属性。 可以看到常用的...
  • 虽然说它的使用频率并不高,但是它对我们深入理解View的工作原理上具有重要的作用,本文将结合源码介绍LayoutParams的相关知识。 LayoutParams是什么,有什么用 LayoutParams翻译成汉语就是布局参数,每个控
  • 1. 原理说明: 我们知道,在 RelativeLayout 布局中有很多特殊的属性,通常在载入布局之前,在相关的xml文件中进行静态设置即可。 但是,在有些情况下,我们需要动态设置布局的属性,在不同的条件下设置不同的...
  • 2.实现很有意思的一个效果,原理其实很简单,就是通过监听ScrollView在Y轴的滑动距离,然后在代码中动态设置头像的位置和大小。public class MainActivity extends AppCompatActivity { private CircleImageView ...
  • 这段时间在学习android中view的工作原理与自定义View的相关内容,所以未来这这几篇博客都总结一下相关的知识吧。 首先我们要了解和熟悉两个概念,DecorView 与 MeasureSpec. DecorView 我们在设置Activity的界面时,...
  • 1. 原理说明:  我们知道,在 RelativeLayout 布局中有很多特殊的属性,通常在载入布局之前,在相关的xml文件中进行静态设置即可。  但是,在有些情况下,我们需要动态设置布局的属性,在不同的条件下设置不同的...
  • 用了我一个周末的时间,个中愤懑就不说了,就这个问题,我翻遍全球网络没有一篇像样的资料,现在将实现原理简单叙述如下: 调用WindowManager,并设置WindowManager.LayoutParams的相关属性,通过WindowManager的...
  • View工作原理思维导图ViewRoot和DecorViewMeasureSpec理解MeasureSpecMeasureSpec和LayoutParams关系View的工作流程measure过程正确获取宽高方法layout过程draw过程参看文章 ViewRoot和DecorView 这是在View三大...
  • View工作原理

    2017-08-01 15:02:42
    在自定义View的时候,掌握View的底层工作原理,也就是:View的measure、Layout、draw流程,可以帮助我做出比较有意思的自定义View。因此,本文主要讲解: View的工作原理,其中包括:...MeasureSpec和LayoutParams
  • Anko原理

    2018-11-18 11:35:41
    ViewManager 在了解anko之前,我们必须要先了解一下ViewManager这个类,这个是一个接口,通过这个接口,我们可以在Activity中添加、移除...public void addView(View view, ViewGroup.LayoutParams params); public ...
  • view的绘制原理

    2018-11-16 16:07:18
    1.ViewGroup.LayoutParams类() &nbsp; ViewGroup 的子类(RelativeLayout、LinearLayout)有其对应的ViewGroup.LayoutParams 子类 &nbsp;&nbsp;如:RelativeLayout的 ViewGroup.LayoutParams子类 = ...
  • View的绘制原理

    2018-08-24 14:54:01
    参考博客;... 知识储备 1.ViewGroup.LayoutParams类()  ViewGroup 的子类(RelativeLayout、LinearLayout)有其对应的ViewGroup.LayoutParams 子类 ... 如:RelativeLayout的 ViewGroup.LayoutParams子类...
  • View的工作原理

    2020-05-22 00:36:50
    MeasureSpec和LayoutParams的对应关系3. View的工作流程1. measure过程1. View的measure过程2. ViewGroup的measure过程2. layout过程3. draw过程 1. 初识ViewRoot 和 DecorView ViewRoot ViewRoot对应于...
  • 转载请注明出处:...测量/布局/绘制顺序 如何引起View的测量/布局/绘制? PerformTraversales() ViewRoot View工作基本流程 MeasureSpec SpecMode MeasureSpec和LayoutParams RootMeasureSpec 测量

空空如也

空空如也

1 2 3 4 5 ... 10
收藏数 181
精华内容 72
关键字:

layoutparams原理