Android 自定义View总结

昨夜雨疏风骤。浓睡不消残酒。试问卷帘人,却道“海棠依旧”。知否,知否?应是绿肥红瘦!

  一首李清照的《如梦令·昨夜雨疏风骤》送给大家。

本篇博客只是一篇总结,自定义View往往和奇奇怪怪的需求相关。面对不断变化的需求,千万不能“死记硬背”,更重要的是要掌握自定义View的流程。

Android中每个控件都会在界面中占得一块矩形区域,这些控件大致被分为两类,即View控件和ViewGroup控件。ViewGroup控件可以包含多个View控件,并且能管理其包含的View控件。结构如下:
View结构图

1. 自定义View

     1. View的测量
     Android系统给我们提供了MeasureSpec类来帮助我们测量View,Measure是一个32位的int值。高2位为测量的模式,低30位为测量的大小。测量的模式可以分为以下三种:
  • EXACTLY 精确值模式。例如:android:layout_width="100dp|match_parent"
  • AT_MOST 最大值模式。例如:android:layout_width="wrap_content"控件的大小一般随着控件的子空间或内容的变化而变化,此时控件的尺寸只要不超过父控件允许的最大尺寸即可。
  • UNSPECIFIED 不指定其大小的测量模式。View想多大就多大,通常在绘制自定义View时使用。
    下面是一套通配的代码,可以作为模板使用。
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    private int measureWidth(int widthMeasureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            result = 200; //单位px
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }
        return result;
    }
     2.在View中通常有以下一些比较重要的回调方法。
    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 回调该方法进行测量
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        // 确定显示位置
    }

    @Override
    protected void onDraw(Canvas canvas) { // 画布
        super.onDraw(canvas);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) { // 触摸事件
        return super.onTouchEvent(event);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) { // 组件大小改变时回调
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onFinishInflate() { // 从XML加载组件后回调
        super.onFinishInflate();
    }
    3. 三种方式实现自定义控件及一般步骤
     1. 对已有控件进行拓展 ----> extends TextView
      ` @Override 
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // 在回调父类方法前,实现自己的逻辑
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            // 在回调父类方法后,实现自己的逻辑
         }`
     2. 通过组合控件来实现新的控件 ----> extends FrameLayout
      1. new 元素
      2. 设置属性(可以自定义属性)
      3. 定义接口(若有需求)
     3. 重写View实现全新控件 ----> extends View
      1. onMeasure()
      2. onLayout()(可选)
      3. onDraw()
      4. onTouchEvent()...
      注:调用invalidate()方法进行重绘可实现动态效果。
自定义属性
    1. 在res目录的values目录下创建一个attrs.xml文件。例如:
<resources>
    <declare-styleable name="topBar">
        <attr name="title" format="string"/>
        <attr name="titleTxtSize" format="dimension"/>
    </declare-styleable>
</resources>
    2. 获取自定义的属性
    private void intView(AttributeSet attrs, Context context) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.topBar);
        String titleTxt = a.getString(R.styleable.topBar_titleTxt);
        float titleTxtSize = a.getDimension(R.styleable.topBar_titleTxtSize, 0);
        a.recycle();
    }
 3. 指定XML命名空间
xmlns:dyk="http://schemas.android.com/apk/res/com.example.testandroid"
dyk:titleTxt="test"

2. 自定义ViewGroup

    自定义ViewGroup通常需要重写onMeasure()方法来对子View进行测量,重写onLayout()方法确定子View的位置,重写onToutchEvent()方法增加响应事件。
    注:new对象时,调用一个参数的构造方法。未使用自定义属性时,调用两个参数的构造方法,使用自定义属性时调用三个参数的构造方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值