Android开发之自定义View

作者: Reathin | 来源:发表于2017-06-04 11:07 被阅读98次

    自定义控件

    使用场景: 在实际开发中经常会遇到现有的UI控件不能满足项目需求,或一个功能涉及到多个UI控件的组合,或实现某一特效的UI,这时必须通过自定义View的方式,实现这些功能,例如股票的实时统计图、电子书等。

    分类

    绘制控件 - 自绘控件

    1.继承View
    需要自定义绘制内容,需要继承View,必须要重写onDraw方法,在onDraw方法中来进行绘制,实现onMeasure方法,来测量控件的空间。

    2.继承ViewGroup

    • 通过在ViewGroup中通过this.addView(<控件对象>)来添加控件
    • onMeasure方法,来测量控件的空间
    • onLayout方法必须实现,在此方法中处理子控件的位置。当视图初始化,或者视图位置发生改变时候,调用此方法。

    组合控件

    通过继承系统已经存在的视图容器,在初始化时候,直接加载布局

    mInflater.inflate(<布局资源的ID>,this);
    mIvBack = (ImageView) findViewById(R.id.btn_back);
    

    继承控件

    通过继承系统已经存在的视图或者视图容器,在内部改变此视图或者视图容器的功能
    例如:通过改变ListView添加删除功能

    自定义View步骤

    • 创建类,继承View及View的子类,并提供相关的构造方法
    • 重写onMeasure()方法,并调用setMeasuredDimension(int width, int height)设置控件的大小
    • 重写onDraw()方法,实现绘制特定内容
    • 重写onTouchEvent()方式处理触摸事件
    • 在布局文件中使用<类全名>并设置属性

    自定义View属性

    1.位置:res/values/attrs.xml

    2.属性集

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <!-- 声明属性集 -->
        <declare-styleable name="LabelView">
            <attr name="text" format="string"/>
            <attr name="textSize" format="dimension"/>
            <attr name="textColor" format="color" />
        </declare-styleable>
    </resources>
    

    3.指定属性名及其内容格式
    例:<attr name="text" format="string" />

    string 字符型
    integer 整数型
    dimension 尺寸值
    color 颜色值
    reference 参考某一资源ID
    boolean:布尔值

    使用自定义View属性

    在布局控件标签中引用:xmlns:my="http://schemas.android.com/apk/res/{package_name}"
    或xmlns:app="http://schemas.android.com/apk/res-auto"
    在自定义控件中使用:my:text=““或app:text=""

    在自定义View的View(Context context, AttributeSet attrs)构造方法中,获取自定义属性的值

    //TypedArray是一个用来存放由context.obtainStyledAttributes获得的属性的数组
            //在使用完成后,一定要调用recycle方法
             TypedArray ta = context.obtainStyledAttributes(attrs,
                        R.styleable.LabelView);
    
                CharSequence s = ta.getString(R.styleable.LabelView_text);
                if (s != null) {
                    setText(s.toString());
                }
    
                setTextColor(ta.getColor(R.styleable.LabelView_textColor, 0xFF000000));
    
                int textSize = ta.getDimensionPixelSize(R.styleable.LabelView_textSize, 0);
                if (textSize > 0) {
                    setTextSize(textSize);
                }
                ta.recycle();
    

    涉及相关类

    View 类

    • View(Context) 动态实例化控件的构造方法
    • View(Context context, AttributeSet attrs) 布局中使用控件的构造的方法
    • onMeasure(int widthMeasureSpec, int heightMeasureSpec) 自定义控件时重写的方法,用于测量控件大小
    • onDraw(Canvas canvas) 在自义控件上绘制相关内容
    • onTouchEvent(MotionEvent) 实现触摸事件处理方法
    • setPadding(int l,int t,int r,int b) 设置内部间距
    • layout(int l, int t, int r,int b) 改变控件位置的方法
    • requestLayout() //清除布局,获取新的布局空间(刷新UI,重新调用onDraw()方法绘制UI)
    • invalidate() //重新绘制新的数据(刷新UI,重新调用onDraw()方法绘制UI)

    MeasureSpec 测量空间工具类

    • int MeasureSpec.getMode(mSpec) 获取控件大小模式
      • MeasureSpec.EXACTLY,确切空间,布局中的属性值一般为match_parent或160dp固定值
      • MeasureSpec.AT_MOST 尽量多的空间,布局中的属性值wrap_content
      • MeasureSpec.UNSPECIFIED 未指定的,一般在父控件中使用
    • MeasureSpec.getSize(mSpec) 获取控件大小

    TypedArray 属性数组类

    • TypeArray Context.obtainStyledAttributes(attrs,R.styleable.LabelView) 获取指定attrs中的所有属性
    • String getString(R.styleable.LabelView_text) 获取指定属性的文本值
    • int getDimensionPixelSize(R.styleable.LabelView_textSize, 0) 获取指定属性的间距值
    • int getColor(R.styleable.LabelView_textColor, 0xFF000000) 获取指定属性的颜色值

    Paint 画笔类

    • Paint.setAntiAlias(true) 启用抗锯齿
    • Paint.setTextSize(int pixes) 设置字体大小,像素,一般转成sp
    • Paint.setColor(int color) 设置颜色
    • Paint.setStyle(Paint.Style) 设置画笔样式
    • float mTextPaint.measureText(String) 测量文字的大小
    • Paint.ascent() 获取文字基准线以上到文字顶部的间距,负数
    • Paint.descent() 获取文字基准线以下到文字底部的间距

    Canvas 画布类

    • canvas.drawText(String,int x,int y,Paint) 绘制文本
    • canvas.drawRoundRect(RectF,int rx,int ry,Paint) 绘制圆角四边方形
    • canvas.drawBitmap(bitmap, left, top, paint) 绘制图片
    • canvas.drawCircle(cx, cy, radius, paint) 绘制圆
    • canvas.drawLine(startX, startY, stopX, stopY, paint) 绘制线条

    Xfermode 两个图层的转换模式

    Xfermode有三个子类 :
    AvoidXfermode 指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。
    PixelXorXfermode 当覆盖已有的颜色时,应用一个简单的像素异或操作。
    PorterDuffXfermode 这是一个非常强大的转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。


    要应用转换模式,可以使用setXferMode方法,如下所示:

    AvoidXfermode avoid = new AvoidXfermode(Color.BLUE, 10, AvoidXfermode.Mode. AVOID);
    borderPen.setXfermode(avoid);

    PorterDuff.Mode为枚举类,一共有16个枚举值:

    1.PorterDuff.Mode.CLEAR
    所绘制不会提交到画布上。
    2.PorterDuff.Mode.SRC
    显示上层绘制图片
    3.PorterDuff.Mode.DST
    显示下层绘制图片
    4.PorterDuff.Mode.SRC_OVER
    正常绘制显示,上下层绘制叠盖。
    5.PorterDuff.Mode.DST_OVER
    上下层都显示。下层居上显示。
    6.PorterDuff.Mode.SRC_IN
    取两层绘制交集。显示上层。
    7.PorterDuff.Mode.DST_IN
    取两层绘制交集。显示下层。
    8.PorterDuff.Mode.SRC_OUT
    取上层绘制非交集部分。
    9.PorterDuff.Mode.DST_OUT
    取下层绘制非交集部分。
    10.PorterDuff.Mode.SRC_ATOP
    取下层非交集部分与上层交集部分
    11.PorterDuff.Mode.DST_ATOP
    取上层非交集部分与下层交集部分
    12.PorterDuff.Mode.XOR
    异或:去除两图层交集部分
    13.PorterDuff.Mode.DARKEN
    取两图层全部区域,交集部分颜色加深
    14.PorterDuff.Mode.LIGHTEN
    取两图层全部,点亮交集部分颜色
    15.PorterDuff.Mode.MULTIPLY
    取两图层交集部分叠加后颜色
    16.PorterDuff.Mode.SCREEN
    取两图层全部区域,交集部分变为透明色

    相关文章

      网友评论

      • xiaoxuan0115:自定义viewgroup需要重写ondraw方法么?我咋记得正常情况下ondraw方法是不执行的,有点疑惑,求楼主解答
        Gunter1993: @xiaoxuan0115 dispatchDraw(canvas)
        Reathin: @xiaoxuan0115 正常不执行onDraw()

      本文标题:Android开发之自定义View

      本文链接:https://www.haomeiwen.com/subject/uvevfxtx.html