最近在写程序中,遇到了之前自己没遇到过的代码,一番理解后才知道原来是在动态设定xml布局中的属性。即利用LayoutParams可以动态的设定布局或者控件的宽和高,以及的它的左间距,右间距,内间距,和gravity等。总之,我们在xml中可以设定的东西,用代码都是可以搞定的。每一种布局都会对应自己的LayoutParams。于是我也做了下面的实验,算是一个参考范例吧。顺便熟悉一下这方面的知识。

一、线性布局的动态设定属性值

一如往常,我们新建一个android项目,姑且叫做“View实验”。新建类MyLinearLayout继承自LinearLayout。我们先看它里面的代码再做解释。如下:

 package com.fuly.view;

 import android.content.Context;
import android.util.AttributeSet;
import android.widget.Button;
import android.widget.LinearLayout; public class MyLinearLayout extends LinearLayout{ private boolean once = false; public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
} protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if(!once){
this.setGravity(Gravity.CENTER); Button btn = new Button(getContext());
btn.setText("按钮");
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); addView(btn,lp);
once = true;
} setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());
} }

代码比较简单,就是定制自己的LinearLayout。只是往里面加入了一个按钮而已,其实用xml可以轻松实现,这里为了学习新的东西,我们就用代码实现。代码的第20行就是设定MyLinearLayout的内容要是居中排列的。代码的第24行就是新建一个线性布局的LayoutParams,设定它的宽和高。代码的第27行就是addView,即加入子view的意思,同时设定子view的属性,即lp。这样子我们就完成了将一个按钮添加到MyLinearLayout中。

可能还有些代码你不是很明白。首先你要了解一个view的完整的绘制流程,这个在后面专门说一说。一个view完整绘制出来显示在屏幕上,需要经过onMeasure阶段。在这个方法要做的就是测量view的大小和规格。因为我们可以重写这个方法来私人定制我们的view的大小。第31行的代码就是设定MyLinearLayout的大小的。我们看在这里并没有设定为另外一个值,仍旧是采用了xml中的,其实getMeasureWidth()和getMeasureHeight()在这里获取的就是xml文件里设定的layout_width和layout_height的值。关于这两个方法后面还会再说到。之所以要用布局变量once,是为了避免重复执行那段代码,这样就是不断的加入很多个按钮了。因为onMeasure()方法可能会执行很多次。好了,这样子,上面的那段代码你应该能够完全理解了。

然后将MyLinearLayout加入到xml中,代码如下:

 <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"
> <com.fuly.view.MyLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
> </com.fuly.view.MyLinearLayout> </RelativeLayout>

MainActivity的代码不需更改。就这样子,我们来运行一下程序,看看效果,如下:

效果达到了,对动态设定布局有一定的感觉了吧。下面来说一说view的绘制过程吧,然后再实现一个较复杂的动态设定布局的例子。这样子对这方面的知识应该会更加的熟悉。

二、view的绘制流程以及更新和重绘制

关于view的绘制流程及其更新重绘网上有好多大牛都讲过了,这里推荐郭霖的博客中的讲解。我也是从这里学习的。在这里我就简洁的说一说,原理性的东西就百度看大牛的讲解吧。

一个view完整的绘制显示在屏幕上,需要依次,注意是依次经过以下流程:

(1)onMeasure阶段(其实是measure阶段)。这这个方法里,要确定的是view的大小个规格。方法中传入的两个参数其实就是我们在xml中设定的layout_width和layout_height所封装的信息。关于这两个参数widthMeasureSpec和heightMeasureSpec,下面会详细说。因此我们想重新设定view大小,就可以重写这个方法来设定。但是注意,在我们重写时,一定要在最后使用setMeasuredDimension();方法来设定我们想要的宽和高,这个方法就是用来干这个的。而getMeasureWidth和getMeasureHeight就是在onMeasure方法执行后才能调用的,否则获得永远是0.它们获取的其实就是setMeasuredDimension方法里面所设定的宽和高的值。需要注意的是,onMeasure可能会多次执行,因为有子view存在时,就会不断执行该方法来测量每一个子view的大小。

(2)接着执行onLayout()方法。在执行了onMeasure方法后,我们就已经知道了每个view的大小了。如果要绘制,光知道大小还不行,还要知道位置,而onLayout方法就是干这个的。因此我们想重新设定位置,可以来重写这个方法。这个方法代码如下:

 protected void onLayout( int l, int t, int r, int b) {
// TODO Auto-generated method stub
super.onLayout(l, t, r, b);
}

四个参数分别表示view的左上右下的坐标,注意是左上右下,而不是什么左上角坐标和右下角坐标。

(3)紧接着执行onDraw方法。现在大小和位置都知道了,就可以开始绘制了,即执行onDarw方法。因此我们如果想绘制出什么东西,重写这个方法即可。一般不建议将添加子view的代码放在这里。

下面具体说一说widthMeasureSpec和wheightMeasureSpec这两个参数。

其实它们就是用来确定视图的宽度和高度的,封装了两个信息:大小和规格。这样,MeasureSpec的值由两部分组成,分别是SpecSize和SpecMode,SpceSize记录的是大小,SpecMode记录的是规格。大小是很直白的,而关于规格,即SpecMode有以三种:

1. EXACTLY

表示父视图希望子视图的大小应该是由specSize的值来决定的,系统默认会按照这个规则来设置子视图的大小,开发人员当然也可以按照自己的意愿设置成任意的大小。

2. AT_MOST

表示子视图最多只能是specSize中指定的大小,开发人员应该尽可能小得去设置这个视图,并且保证不会超过specSize。系统默认会按照这个规则来设置子视图的大小,开发人员当然也可以按照自己的意愿设置成任意的大小。

3. UNSPECIFIED

表示开发人员可以将视图按照自己的意愿设置成任意的大小,没有任何限制。这种情况比较少见,不太会用到。

关于它们的方法有:

 MeasureSpec.getMode(measureSpec)   获得规格
2 MeasureSpec.getSize(measureSpec) 获得大小
3 int height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY); 这个就是设定大小和规格了

下面就是说一说view刷新和重绘

这个就说两个方法吧,如下:

View.requestLayout()   请求重新布局,重新调用:onMeasure,onLayout,onDraw;

View.invalidate()        刷新视图,相当于调用View.onDraw()方法

然后再说两种获取宽和高的区别

现在你可能出现疑问了,getMeasureHeight()和getHeight()方法到底有什么区别呢??其实它们的区别还是挺大的,解释如下

getMeasureHeigth()和getMeasureWidth()方法获取的宽和高是onMeasure方法中设定的宽度和高度

而getHeight()和getWidth()获得是view的getTop()-getBottum()以及getRight()-getLeft(),即onLayout方法中的坐标相减去的值

三、动态设定布局RelativeLayout

好了,这篇文章主要是介绍动态设定布局的。所以还是要回到主干线上来。现在有了view绘制流程的基础,相信下面的代码理解起来比较容易。下面我们动态设定一个相对布局,比起上面稍微复杂一点。注释很详细了。我就不多说了。

我们只需要修改上面的MyLinearLayout即可,其他的都不需要改。代码如下:

 package com.fuly.view;

 import android.content.Context;
import android.util.AttributeSet;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView; public class MyLinearLayout extends RelativeLayout{ private boolean once = false; public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
} protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if(!once){
this.setPadding(3, 3, 3, 3);//首先设定四个方向的内边距
//首先设定按钮
Button btn = new Button(getContext());
btn.setText("按钮");
btn.setId(1);//设定id,
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.leftMargin = 5;//设定左边距
lp.addRule(ALIGN_PARENT_LEFT);//设定位于最左边
addView(btn,lp); //然后再添加一个TextView
TextView tv = new TextView(getContext());
tv.setId(2);
tv.setText("我在你右边");
tv.setTextSize(30);
LayoutParams lp2 = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.MATCH_PARENT);
lp2.addRule(RIGHT_OF, btn.getId());//设定在按钮的右边
addView(tv,lp2); //再添加一个TextView吧
TextView tv2 = new TextView(getContext());
tv2.setText("我在最底部");
tv2.setTextSize(30);
LayoutParams lp3 = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
lp3.bottomMargin = 3;
lp3.addRule(ALIGN_PARENT_BOTTOM);
lp3.addRule(CENTER_HORIZONTAL);
addView(tv2,lp3);
once = true;
} setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());
} }

好了,运行一下,看看我们的显示效果吧:

android之对于view的一点深入理解的更多相关文章

  1. [转]Android View.onMeasure方法的理解

    转自:http://blog.sina.com.cn/s/blog_61fbf8d10100zzoy.html Android View.onMeasure方法的理解 View在屏幕上显示出来要先经过 ...

  2. Android开发艺术探索第五章——理解RemoteViews

    Android开发艺术探索第五章--理解RemoteViews 这门课的重心在于RemoteViews,RemoteViews可以理解为一种远程的View,其实他和远程的Service是一样的,Rem ...

  3. Android 判断一个 View 是否可见 getLocalVisibleRect(rect) 与 getGlobalVisibleRect(rect)

    Android 判断一个 View 是否可见 getLocalVisibleRect(rect) 与 getGlobalVisibleRect(rect) [TOC] 这两个方法的区别 View.ge ...

  4. 1.Android 视图及View绘制分析笔记之setContentView

    自从1983年第一台图形用户界面的个人电脑问世以来,几乎所有的PC操作系统都支持可视化操作,Android也不例外.对于所有Android Developer来说,我们接触最多的控件就是View.通常 ...

  5. android中实现view可以滑动的六种方法续篇(二)

    承接上一篇,上一篇中讲解了实现滑动的第五种方法,如果你还没读过,可点击下面链接: http://www.cnblogs.com/fuly550871915/p/4985482.html 这篇文章现在来 ...

  6. android中实现view可以滑动的六种方法

    在android开发中,经常会遇到一个view需要它能够支持滑动的需求.今天就来总结实现其滑动的六种方法.其实每一种方法的 思路都是一样的,即:监听手势触摸的坐标来实现view坐标的变化,从而实现vi ...

  7. Android 自己定义View学习(2)

    上一篇学习了基本使用方法,今天学一下略微复杂一点的.先看一下效果图 为了完毕上面的效果还是要用到上一期开头的四步 1,属性应该要有颜色,要有速度 <?xml version="1.0& ...

  8. Android 中的View与ViewGroup

    Android重点知识--View和ViewGroup与自定义控件 作者:丁明祥 邮箱:2780087178@qq.com 一.基础 ViewGroup 参考资料: Android 手把手教您自定义V ...

  9. Android读取自定义View属性

    Android读取自定义View属性 attrs.xml : <?xml version="1.0" encoding="utf-8"?> < ...

随机推荐

  1. gihub简单学习 步步操作(简单易学)

    一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 二:SVN与Git的最主要的区别? SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以 ...

  2. FileReader实现上传图片前本地预览

    平时做图片上传预览时如果没有特殊的要求就直接先把图片传到后台去,成功之后拿到URL再渲染到页面上.或者使用前端插件.这篇博客使用的是HTML5的新特性——FileReader.由于兼容性,这种方法不适 ...

  3. php.ini配置max_execution_time和FPM配置request_terminate_timeout

    PHP限定脚本执行时长的方式有几种,下面说下php.ini中的max_execution_time和php-fpm.conf中的request_terminate_timeout 1. php.ini ...

  4. vuex 实现vue中多个组件之间数据同步以及数据共享。

    http://pan.baidu.com/s/1hrJfpli  demo下载地址 前言 在一些项目中有很多数据状态之间要实现数据共享状态共享,例如购物车的数据.用户的登录状态等等.vue父元素是可以 ...

  5. 解决VS2010在新建实体数据模型出现“在 .NET Framework Data Provider for Microsoft SQL Server Compact 3.5 中发生错误。请与提供程序供应商联系以解决此问题。”的问题

    最近想试着学习ASP.NET MVC,在点击 添加--新建项--Visual C#下的数据中的ADO.NET 实体数据模型,到"选择您的数据连接"时,出现错误,"在 .N ...

  6. springMVC @Component-@Resource-@Repository-@Service-@Controller的区别和理解

    作用: @Component------------------------泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注.(Component-------成分; 组分; 零件) @R ...

  7. My SQL查询语言

    基础查询 一.语法select 查询列表from 表名;二.特点1.查询列表可以是字段.常量.表达式.函数,也可以是多个2.查询结果是一个虚拟表 三.示例1.查询单个字段select 字段名 from ...

  8. Python入门-迭代器

    在说迭代器之前,首先来简单说一下函数名的运用以及闭包的概念和应用,有助于我们理解以后的知识. 一.函数名的运用 函数名是一个变量,但它是一个特殊的变量,与括号配合可以执行函数的变量. 1.函数名的内存 ...

  9. easyui grid 里的可编辑text 加清空图标

    $.extend($.fn.datagrid.defaults.editors, { text: { init: function (container, options) { var _opt = ...

  10. 006服务监控看板Hystrix Dashboard

    1.POM配置 和普通Spring Boot工程相比,仅仅添加了Hystrix Dashboard和Spring Boot Starter Actuator依赖 <dependencies> ...