Android 自定义View使用示例(二)
2015-06-09 10:47
459 查看
转载http://www.cnblogs.com/crashmaker/p/3530213.htmlFromcrash_coderlinguowu linguowu0622@gamil.com
前言:上一篇中(Android自定义View)介绍了Android开发中,当系统提供的控件不满足开发者需求的时候,演示如何自定义View,本文将作为上篇的延续,先大体上介绍Android是如何画出界面的,属于前提理论基础,下一篇将重点介绍Android画界面过程中的几个重要方法,如:
1,onMeasure() 2,onLayout() 3,onDraw()
Android绘图的理论基础:
1,我们创建一个Activity来测试上一篇中自定义的View:
a)CustomViewActivity.java
1publicclassCustomViewActivityextendsActivity{ 2 3 @Override 4 protectedvoidonCreate(BundlesavedInstanceState){ 5 //TODOAuto-generatedmethodstub 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.customview_layout); 8 } 9}
b)
customview_layout.xml
1<?xmlversion="1.0"encoding="utf-8"?> 2<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" 3xmlns:app="http://schemas.android.com/apk/res/com.project.summary" 4android:layout_width="match_parent" 5android:layout_height="match_parent" 6android:background="@color/BgColor" 7android:orientation="vertical"> 8 9<com.project.summary.customview.CustomView 10android:id="@+id/customView" 11android:layout_width="wrap_content" 12android:layout_height="wrap_content" 13app:colorValue="@color/textRed" 14app:textSize="20sp" 15app:textString="ThistheCustomView1!!!"/> 16 17</LinearLayout>
c)运行结果:
2,Android是如何实现上图的效果的呢?
a)查看google文档,它给出了如下解释:
WhenanActivityreceivesfocus,itwillberequestedtodrawitslayout.TheAndroidframeworkwillhandletheprocedurefordrawing,buttheActivitymustprovidetherootnodeofitslayouthierarchy.
结合上面的例子来说明一下:当进入CustomViewActivity这个Activity时,该Activity获得焦点,此时,该Activity就会向系统请求绘制出它的布局,这个请求通过Androidframework来处理,前提是:CustomViewActivity必须提供该布局的根结点,从CustomViewActivity.java看出,该Activity提供了R.layout.customview_layout,而该布局的根结点就是我们布局文件的LinearLayout;
b)
Drawingbeginswiththerootnodeofthelayout.Itisrequestedtomeasureanddrawthelayouttree.DrawingishandledbywalkingthetreeandrenderingeachViewthatintersectstheinvalidregion.Inturn,eachViewGroupisresponsibleforrequestingeachofitschildrentobedrawn(withthedraw()method)andeachViewisresponsiblefordrawingitself.Becausethetreeistraversedin-order,thismeansthatparentswillbedrawnbefore(i.e.,behind)theirchildren,withsiblingsdrawnintheordertheyappearinthetree.
从该段文档可以了解到,Android中View的绘制是从布局的根结点开始,开始之前需要遍历整个布局结构,如果是ViewGroup,ViewGroup(如:LinearLayout,RelativeLayout等)需要对它的所有子View进行遍历及绘制,如果只是普通的View(TextView等),那么它只负责对自身进行绘制。
c)
Drawingthelayoutisatwopassprocess:ameasurepassandalayoutpass.Themeasuringpassisimplementedinmeasure(int,int)andisatop-downtraversaloftheViewtree.EachViewpushesdimensionspecificationsdownthetreeduringtherecursion.Attheendofthemeasurepass,everyViewhasstoreditsmeasurements.Thesecondpasshappensinlayout(int,int,int,int)andisalsotop-down.Duringthispasseachparentisresponsibleforpositioningallofitschildrenusingthesizescomputedinthemeasurepass.
绘制需要两个过程,一个是measure(测量大小的)过程,一个是layout(计算绘制位置的)过程:
1)measure过程:需要在measure()方法中实现,并且是自顶向下地遍历测量View的树形结构,测量完后,各结点将它的测量规格(specifications)存放在该树形结构中;
2)layout过程:通过调用layout(int,int,int,int)方法,每一个父View负责子View的绘制位置,而子View的最终大小,则是通过measure过程计算出来的大小。
d)
WhenaViewobject'smeasure()methodreturns,itsgetMeasuredWidth()andgetMeasuredHeight()valuesmustbeset,alongwiththoseforallofthatViewobject'sdescendants.AViewobject'smeasuredwidthandmeasuredheightvaluesmustrespecttheconstraintsimposedbytheViewobject'sparents.Thisguaranteesthatattheendofthemeasurepass,allparentsacceptalloftheirchildren'smeasurements.AparentViewmaycallmeasure()morethanonceonitschildren.Forexample,theparentmaymeasureeachchildoncewithunspecifieddimensionstofindouthowbigtheywanttobe,thencallmeasure()onthemagainwithactualnumbersifthesumofallthechildren'sunconstrainedsizesistoobigortoosmall(thatis,ifthechildrendon'tagreeamongthemselvesastohowmuchspacetheyeachget,theparentwillinterveneandsettherulesonthesecondpass).
当每个View对象的measure()方法返回时,每个View的测量宽度值跟测量高度值必须已经被设置,且这两个值是与该View对象的父View相互作用下得来的,并不是说每个View对象都能请求到它任意想得到的值,如果这个View对象请求的宽度或者高度不合理,那么,这个View对象的父View,将再次调用measure()方法,再次确定这个View对象的最终宽度和高度,这个将在后面的onMeasure()过程详细说明中解释;
e)
Themeasurepassusestwoclassestocommunicatedimensions.TheViewGroup.LayoutParamsclassisusedbyViewobjectstotelltheirparentshowtheywanttobemeasuredandpositioned.ThebaseViewGroup.LayoutParamsclassjustdescribeshowbigtheViewwantstobeforbothwidthandheight.Foreachdimension,itcanspecifyoneof: 1)anexactnumber: 2)MATCH_PARENT: whichmeanstheViewwantstobeasbigasitsparent(minuspadding) 3)WRAP_CONTENT: whichmeansthattheViewwantstobejustbigenoughtoencloseitscontent(pluspadding). TherearesubclassesofViewGroup.LayoutParamsfordifferentsubclassesofViewGroup.Forexample,RelativeLayouthasitsownsubclassofViewGroup.LayoutParams,whichincludestheabilitytocenterchildViewobjectshorizontallyandvertically. MeasureSpecobjectsareusedtopushrequirementsdownthetreefromparenttochild.AMeasureSpeccanbeinoneofthreemodes: UNSPECIFIED:ThisisusedbyaparenttodeterminethedesireddimensionofachildView.Forexample,aLinearLayoutmaycallmeasure()onitschildwiththeheightsettoUNSPECIFIEDandawidthofEXACTLY240tofindouthowtallthechildViewwantstobegivenawidthof240pixels. EXACTLY:Thisisusedbytheparenttoimposeanexactsizeonthechild.Thechildmustusethissize,andguaranteethatallofitsdescendantswillfitwithinthissize. ATMOST:Thisisusedbytheparenttoimposeamaximumsizeonthechild.Thechildmustguaranteethatitandallofitsdescendantswillfitwithinthissize.
测量过程使用两个类与dimensions(尺寸)进行通讯,这两个类分别是ViewGroup.LayoutParams和MeasureSpec
ViewGroup.LayoutParams:
用来让View对象告诉他的父View,它需要如何被测量和放置在什么位置,然而,ViewGroup.LayoutParams只是单方面地描述它自己想要多大的宽度和高度而已,并不是最终绘制出来的宽度和高度,ViewGroup.LayoutParams可以指定为以下的值:
1)anexactnumber: 具体的数值; 2)MATCH_PARENT: 与父容器一样的大小; 3)WRAP_CONTENT: 本身该多大就多大,根据该View的内容而定,如TextView中,如果将其宽度设置为wrap_content,那么,它将随着text的长度而改变它的宽度。
MeasureSpec:
该对象封装了父容器传递给子元素的布局要求,它有三种模式:
1) UNSPECIFIED:父容器对子元素没有要求,子元素可以得到任意值; 2)
EXACTLY:父窗口决定子元素的大小,子元素将被限定在给定的边界里而忽略它本身大小; 3)
ATMOST:子元素至多达到父窗口指定的大小,子元素不能超过这个边界;
相关文章推荐
- android实习期日常笔记(二)
- Android GridView实现滚动到指定位置的方法
- 传智播客Android7.16日入驻大广州
- android学习之---基本问题1
- AndroidのListView包含CheckBox时滑动丢失选中状态的解决
- Android NDK (学习笔记五) —— java层和native层进行字符串的交互处理
- Android 利用sharepreference保存应用程序状态
- Android Design Support Library使用详解
- java.lang.ClassCastException: 。。。$LayoutParams cannot be cast to android.widget.LinearLayout$Layout
- Android调用系统相机拍照并获取图片
- android中Parcelable接口的使用
- Android 调用QQ登录
- android 自定义view 圆形进度条
- android开发环境安装与配置
- 如何获取Android唯一标识(唯一序列号)
- Android studio导入项目(出现的问题)
- Android安卓中循环录像并检测内存卡容量
- Android编译系统参考手册
- Android Studio 快捷键(MAC)
- Android实战简易教程-第十二枪(ViewFlipper实现幻灯效果)