自定义View系列(一)

2017已至年尾,工作也告一段落了,感觉好久没有更新博客了。工作中遇到了不少问题,好在都一一解决了。

其实关于自定义View这个问题,我一直都感觉到有点头疼,遇到问题的时候总是去百度,或者自己摸索,很是花费时间,本着学习的态度,在此记录一些关于自定义view的探索过程。废话不多说。首先我们了解一下View的生命周期(还是老习惯,先上代码再解释)。

1、一个简单的自定义View(只列举了部分方法):

public class MyTextView extends View {
    public MyTextView(Context context) {
        this(context,null);
    }

    public MyTextView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        Log.i("wls", "TextView: " + "TextView");
    }

    @Override
    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        Log.i("wls", "onVisibilityChanged: " + "onVisibilityChanged");
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        Log.i("wls", "onSizeChanged: " + "onSizeChanged");
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        Log.i("wls", "onFinishInflate: " + "onFinishInflate");
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.i("wls", "onConfigurationChanged: " + "onConfigurationChanged");
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        Log.i("wls", "onMeasure: " + "onMeasure");
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        Log.i("wls", "onLayout: " + "onLayout");
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.i("wls", "onDraw: " + "onDraw");
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        Log.i("wls", "onKeyDown: " + "onKeyDown");
        return super.onKeyDown(keyCode, event);

    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        Log.i("wls", "onKeyUp: " + "onKeyUp");
        return super.onKeyUp(keyCode, event);
    }
}

2、在布局中引用:

<android.support.constraint.ConstraintLayout
    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"
    tools:context="com.example.administrator.myview1.MainActivity">

    <com.example.administrator.myview1.MyTextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible"/>

</android.support.constraint.ConstraintLayout>

很是简单,运行了一下,发现打印顺序:

02-09 10:16:41.733 18938-18938/com.example.administrator.myview1 I/wls: TextView: TextView
02-09 10:16:41.733 18938-18938/com.example.administrator.myview1 I/wls: onFinishInflate: onFinishInflate
02-09 10:16:41.773 18938-18938/com.example.administrator.myview1 I/wls: onVisibilityChanged: onVisibilityChanged
02-09 10:16:41.773 18938-18938/com.example.administrator.myview1 I/wls: onMeasure: onMeasure
02-09 10:16:41.773 18938-18938/com.example.administrator.myview1 I/wls: onMeasure: onMeasure
02-09 10:16:41.833 18938-18938/com.example.administrator.myview1 I/wls: onMeasure: onMeasure
02-09 10:16:41.833 18938-18938/com.example.administrator.myview1 I/wls: onMeasure: onMeasure
02-09 10:16:41.833 18938-18938/com.example.administrator.myview1 I/wls: onSizeChanged: onSizeChanged
02-09 10:16:41.833 18938-18938/com.example.administrator.myview1 I/wls: onLayout: onLayout
02-09 10:16:41.853 18938-18938/com.example.administrator.myview1 I/wls: onMeasure: onMeasure
02-09 10:16:41.853 18938-18938/com.example.administrator.myview1 I/wls: onMeasure: onMeasure

02-09 10:16:41.853 18938-18938/com.example.administrator.myview1 I/wls: onLayout: onLayout

02-09 10:16:41.853 18938-18938/com.example.administrator.myview1 I/wls: onDraw: onDraw


这里我们按照log打印顺序进行一一解释:

TextView:MyTextView的构造函数,这个没什么好说的,只要你调用的这个View就会执行这个方法,一般会在里面做一些初   始化的东西(如果有自定义属性,也是这构造方法中进行获取);

onFinishInflate:该方法当View及其子View从XML文件中加载完成后会被调用。这个方法没什么意义,紧跟着View的构造方法    执行;

onVisibilityChanged:这个很好理解,只要View是否显示的状态发生变化,就会调用这个方法;

onMeasure:这个算是比较重要的了。这个方法在计算当前View及其所有子View尺寸大小需求时会被调用,一般情况下,在自定义View的时候,都会重写这个方法,onMeasure中有两个参数:widthMeasureSpec,heightMeasureSpec。

系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。

所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法”:

重写之前先了解MeasureSpec的specMode,一共三种类型:

EXACTLY:一般是设置了明确的值或者是MATCH_PARENT

AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT

UNSPECIFIED:表示子布局想要多大就多大,很少使用

View默认的onMeasure()方法只支持EXACTLY模式,所以如果在自定义控件的时候不重写onMeasure()方法的话,就只能使用EXACTLY模式,且控件只可以响应你指定的具体宽高值或者是match_parent属性。如果要让自定义的View支持wrap_content属性,那么就必须重写onMeasure()方法来指定wrap_content时的大小至于这个方法为什么执行那么多次,我也不明白······

onSizeChanged:这个方法是当View的大小发生变化的时候调用;

onLayout: 这个方法是对View视图进行布局,onMeasure对View进行测量,测量之后即可获得View的大小,通过onLayout确定View的位置。onlayout中接收了5个参数:changed,left,top,right,bottom。changed:这个是判断当前View的大小和位置是否发生了变化。剩下的四个参数。left,top,right,bottom就比较容易理解了,指的是View在其父布局ViewGroup中的位置。(这个方法在自定义布局的时候调用)

onDraw:顾名思义,就是绘制的意思,上面通过onMeasure和onLayout两个方法之后,View的大小和位置都确定了,接着就是对View进行绘制了。这里有一个参数canvas:就是画布的意思,一般我们自定义控件的时候,都要通过调用canvas这个参数的方法来实现。这个接下来会详细讲解。

onKeyDown:这个是当view中有控件被按下的时候调用,相应的onKeyUp是手指抬起的时候调用;


canvas的常用操作:


图片来自:(http://blog.csdn.net/u014005316/article/details/54667576)

关于View的声明周期就讲到这里,接下来几篇会通过实例着重理解他们的用法!



这个

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值