zoukankan      html  css  js  c++  java
  • android 自定义 view 和 ViewGroup

    ViewGroup的职能为:给childView计算出建议的宽和高和测量模式 ;决定childView的位置;为什么只是建议的宽和高,而不是直接确定呢,别忘了childView宽和高可以设置为wrap_content,这样只有childView才能计算出自己的宽和高。

    View的职责:根据测量模式和ViewGroup给出的建议的宽和高,计算出自己的宽和高;同时还有个更重要的职责是:在ViewGroup为其指定的区域内绘制自己的形态。

    在自定义view中:

    1、自定义View的属性

      通过attrs.xml 添加

    1 <declare-styleable name="CustomTextView">  
    2    <attr name="titleText" />  
    3    <attr name="titleTextColor" />  
    4    <attr name="titleTextSize" />  
    5 </declare-styleable>  

    2、在View的构造方法中获得我们自定义的属性

      通过Context.obtainStyledAttributes获取xml属性。

    3、重写onMesure 

      android提供MeasureSpec类帮助测量view。MeasureSpec是一个32位的int值,其中高两位为测量模式,低30位为测量大小。

      1、EXACTLY

        精确值模式,当我们的控件的layout_width属性和layout_height属性指定为具体数值时,如android:layout_width="100dp"或者为match_parent时系统使用的是EXACTLY模式。

        父控件可以通过MeasureSpec.getSize(measureSpec)直接得到子控件的尺寸。

        父View给自定义View确定了一个范围,在这个范围内,自定义view的大小是给出的具体的值,比如 width =100dp,height=200dp,但是如果给出的任何一个数值超过了父View的限制值,他最大是父View的限制值

      2、AT_MOST

        最大值模式,当控件layout_width属性和layout_height属性为wrap_content时,控件大小随控件子控件或内容变化,此时控件的尺寸只要不超过父控件允许的最大尺寸即可。

        这种模式下,父控件无法确定子 View 的尺寸,只能由子控件自己根据需求去计算自己的尺寸,这种模式就是我们自定义视图需要实现测量逻辑的情况。

      3、UNSPECIFIED

        不指定大小测量模式。父视图不对子视图有任何约束,它可以达到所期望的任意尺寸,比如 ListView、ScrollView,一般自定义 View 中用不到。

        View类默认的onMeasure()方法只支持EXACTLY模式,如果想让控件支持wrap_content属性就必须重写onMeasure()方法

        重写onMeasure()方法后需调用setMeasuredDimension(int measuredWidth,int measuredHeight)

      设置了WRAP_CONTENT时,我们需要自己进行测量,必须重写onMeasure()方法

      

    // ViewRootImpl#getRootMeasureSpec源码:
    private static int getRootMeasureSpec(int windowSize, int rootDimension) {
            int measureSpec;
            switch (rootDimension) {
    
            case ViewGroup.LayoutParams.MATCH_PARENT:
                // Window can't resize. Force root view to be windowSize.
                measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
                break;
            case ViewGroup.LayoutParams.WRAP_CONTENT:
                // Window can resize. Set max size for root view.
                measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
                break;
            default:
                // Window wants to be an exact size. Force root view to be that size.
                measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
                break;
            }
            return measureSpec;
        }

    4、重写onDraw

    *********主要View的执行过程*********:

    (1)构造方法 (2)onFinishInflate (3)onSizeChanged(4)onDraw

    在自定义ViewGroup中:

    1. onMeasure中计算childView的测量值以及模式,以及设置自己的宽和高

    2. onLayout对其所有childView进行定位(设置childView的绘制区域)

      通过getChildCount()获取总子view,getChildAt获取childview调用各自的layout(int, int, int, int)方法。

    ViewGroup不会执行onDraw说明:

    1)ViewGroup默认情况下,会被设置成WILL_NOT_DRAW,这是从性能考虑,这样一来,onDraw就不会被调用了。

    2)如果我们要重要一个ViweGroup的onDraw方法,有两种方法:

            1,在构造函数里面,给其设置一个颜色,如#00000000。

            2,在构造函数里面,调用setWillNotDraw(false),去掉其WILL_NOT_DRAW flag。

    注意,自定义的View在使用的时候一定要写出完整的包名,不然系统将无法找到这个View。

    xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01" 

    Android中实现view的更新有两组方法

    一组是invalidate,另一组是postInvalidate,其中前者是在UI线程自身中使用,而后者在非UI线程中使用。 

    前面要利用Handler结合使用和利用postInvalidate()来实现在线程中刷新界面。 

    1,利用invalidate()刷新界面 
      实例化一个Handler对象,并重写handleMessage方法调用invalidate()实现界面刷新;而在线程中通过sendMessage发送界面更新消息。 

    2,使用postInvalidate()刷新界面 
      使用postInvalidate则比较简单,不需要handler,直接在线程中调用postInvalidate即可。 (*****源码也是通过handler去执行*****)

  • 相关阅读:
    C++字符串转数字,数字转字符串
    [转]基础知识整理
    POJ 3071 Football
    POJ 3744 Scout YYF I
    2013成都Regional:一块木板,几个气球
    HDOJ 4497 GCD and LCM
    POJ 1185 炮兵阵地
    POJ 2031 Building a Space Station
    HDOJ 4717 The Moving Points
    CSU 1328: 近似回文词
  • 原文地址:https://www.cnblogs.com/CharlesGrant/p/4864498.html
Copyright © 2011-2022 走看看