• Android 自定义 View 浅析


    Android 自定义 View 浅析

    概括

    说到自定义 View ,就一定得说说 android 系统的UI绘制流程。再说这个流程之前,我们先看一下在每一个 activity 页面中我们的布局 ui 所处的位置。

    Android UI 界面架构

    从上图就可以知道,我们平时使用的 setContentView() 这个方法就是用来设置 contentview 的。了解了,这个之后,我们还应该了解一下 android 中 view 的继承关系。
    View 的继承关系

    从上面的一张图中,我们可以看出 android 的 UI 控件主要有两种:view 和 viewgroup。那么像我们经常使用的 Button,TextView,ImageView 都属于 view 的范畴!FrameLayout,LinearLayout等都属于 viewgroup 的范畴!了解了这些基本知识之后,我们再来说说如果自定义控件!

    如何自定义

    我们要自定义控件,无非就是继承 view 或者 viewgroup 亦或者继承已有的控件在上面在进行扩展!在这里继承 view 和 继承 viewgroup 有点区别!我们先来说说相同点吧!

    相同点

    1. 初始化

    这个其实就是构造函数啦,在这里你可以为这个 view 设置特定的属性啊!那么如何自定义属性呢?首先你得在 res -->
    values 这个目录下新建 attrs 的资源文件!在这个文件中配置你要的自定义属性!先看一下代码

    <?xml version="1.0" encoding="utf-8"?>
    	<resources>
    		<declare-styleable name="WeekSelectView">
        		<attr name="selectColor" format="color"></attr>
        		<attr name="unSelectColor" format="color"></attr>
        		<attr name="lineColor" format="color"></attr>
       		 	<attr name="textColor" format="color"></attr>
        		<attr name="textSize" format="dimension"></attr>
        		<attr name="selectSize" format="dimension"></attr>
        		<attr name="lineWidth" format="dimension"></attr>
        		<attr name="lineHeight" format="dimension"></attr>
        		<attr name="space" format="dimension"></attr>
    		</declare-styleable>
    	</resources>   
    

    其中的 declare-styleable 标签就是添加自定义属性用的,里面包含的每一个 attr 就代表每一个自定义属性!后天面的 format 属性代表每一个属性的类型!接着就是我该如何使用它们呢!我们只要在布局文件中使用代码就行了:

    <com.kidbot.library.widget.weekselect.WeekSelectView 
            xmlns:weekselect="http://schemas.android.com/apk/res-auto"
            android:id="@+id/weekselect"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            weekselect:lineHeight="10dp"
            weekselect:lineWidth="50dp"
            weekselect:selectSize="10dp"
            weekselect:space="30dp"
            weekselect:textSize="15sp" />
    

    要注意的是如果要在布局文件中使用这些自定义属性得加这句话: xmlns:weekselect="http://schemas.android.com/apk/res-auto" 其中 weekselect 这个字段属于用户自定义!
    好了知道如何使用了,那么在写自定义 view 的时候,我们该怎么获取这些这些值呢?

        TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.WeekSelectView);
        selectColor=typedArray.getColor(R.styleable.WeekSelectView_selectColor, Defalut_Select_Color);
        unSelectColor=typedArray.getColor(R.styleable.WeekSelectView_unSelectColor, Defalut_UnSelect_Color);
        lineColor=typedArray.getColor(R.styleable.WeekSelectView_lineColor, Defalut_Line_Color);
        textSize = typedArray.getDimension(R.styleable.WeekSelectView_textSize, Defalut_Text_Size);
        textColor = typedArray.getColor(R.styleable.WeekSelectView_textColor, Defalut_Text_Color);
        selectSize = typedArray.getDimension(R.styleable.WeekSelectView_selectSize, Defalut_Select_Size);
        lineHeight = typedArray.getDimension(R.styleable.WeekSelectView_lineHeight, Defalut_Line_Height);
        lineWidth=typedArray.getDimension(R.styleable.WeekSelectView_lineWidth, Defalut_Line_Width);
        space=typedArray.getDimension(R.styleable.WeekSelectView_space,Defalut_Space);
        typedArray.recycle();
    

    代码比较简单,我就不详细说了,唯一要注意的就是不要忘了释放这个资源

    2. 计算大小

    好了,当我们获取到了 view 的一些初始化值之后呢,我们得计算我们的 view 的大小了!那怎么计算 view 的大小呢?只要覆写 onMeasure(int widthMeasureSpec, int heightMeasureSpec) 这个方法就行了。但在覆写这个方法之前,我们先得了解几个方法

    MeasureSpec.getSize(int value) 这个方法是用来获取对应的宽高的!

    MeasureSpec.getMode(int value) 这个方法是用来获取对应的宽高的模式的!这了模式有这个三个:

    • MeasureSpec.EXACTLY

      精确值模式,当layout_width或layout_height指定为具体数值,或者为match_parent时,系统使用EXACTLY

    • MeasureSpec.AT_MOST

      最大值模式,指定为wrap_content时,控件的尺寸不能超过父控件允许的最大尺寸

    • MeasureSpec.UNSPECIFIED

      不指定测量模式,View想多大就多大,一般不太使用

    这个给出常用的覆写这个方法的代码:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize=MeasureSpec.getSize(widthMeasureSpec);
        int widthMode=MeasureSpec.getMode(widthMeasureSpec);
        int heightSize=MeasureSpec.getSize(heightMeasureSpec);
        int heightMode=MeasureSpec.getMode(heightMeasureSpec);
        if (widthMode==MeasureSpec.EXACTLY){
            width=widthSize;
            lineWidth=(width-itemlength*selectSize-getPaddingRight()-getPaddingLeft()-				textRect.width())/(itemlength-1);
        }else{
            width= (int) (selectSize*(itemlength)+lineWidth*(itemlength-1)+textRect.width());
        }
    
        if (heightMode==MeasureSpec.EXACTLY){
            height=heightSize;
        }else{
            height= (int) (selectSize+space+textRect.height()+paddingTop);
        }
        setMeasuredDimension(width, height);
    }
    

    一般而言,当用户设置了具体的宽高的时候,我们使用设置的,如果没有,我们自己计算对应的宽高,最后设置!当完成这一步之后,我么就可以使用 getMeasuredWidth(),getMeasuredHeight() 这两个方法来获取 view 对应的高度了!

    3. 绘制

    好了,到了这一步,我们只要覆写 onDraw(Canvas canvas) 这个方法就行了,至于要绘制什么,这个是由开发者自己决定的。这里大家住一个问题,就是不要在方法中创建类,要不然会非常的耗资源!!如果大家想绘制出非常炫酷的图形或者效果来,那就得去学学 Canvas 这个类了!!这里给个链接 学习 Canvas

    不同点

    这里我要说的不同点就是如果继承了 viewgroup 之后,要多覆写一个方法 onLayout() 这个方法就是用来设置子view的位置的!
    现在只有你覆写了这个方法之后 ,getHeight()getWidth() 才能获取到对应的值!现在可能有读者要问了,这两个方法和上面的 getMeasuredWidth(),getMeasuredHeight() 这两个方法有什么区别?却别就是

    • getHeight : 就是当前view中的可视高度
    • getMeasuredHeight:就是view的内容高度,包括不可见的地方

    其他要到说的

    自定义view 还有一个比较重要的问题,就是触摸事件,就是 touch 事件 在这个要涉及的问题就是 android 中触摸事件的传递机制了,这个也给个链接 android 触摸事件传递机制学习

    如果触摸相关的已经学习好了,就可以在学习一下 android 动画的相关知识了,毕竟动态的事物比静态的要吸引人啊!这个在给出 android 动画学习

    最后

    希望大家都能学会 android 自定义 view 这个看似高大上的技能,因为这个在 android 开发中太常用了!!!!

  • 相关阅读:
    一个小时前,美国主流媒体,头条,谷歌两位创始人突然宣布退下来,把万亿美元的帝国交给Sundar Pichai
    Fox新闻报道,帮助北朝鲜使用加密货币专家被捕
    看新闻,说墨西哥政府发起了一个军事行动,抓住了11月杀死9位美国人的三名嫌疑犯
    黑五千万不要去商场,就像打仗一样。
    Facebook 一个热搜帖,美国一个老人癌症不治最后的心愿是跟儿子喝啤酒。
    这周末又参加班里同学生日party,同学父母包场2小时花费大约1000美金左右。
    Google谷歌总部员工家庭活动
    800年没有写博客了,今天重新开始。
    iOS image processing with the accelerate framework(透明玻璃效果)
    Custom View Controller Transitions and Storyboard
  • 原文地址:https://www.cnblogs.com/likeandroid/p/5069912.html
Copyright © 2020-2023  润新知