您的位置:首页 > 移动开发 > Android开发

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:子元素至多达到父窗口指定的大小,子元素不能超过这个边界;


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: