自定义View

自定义View

自定义属性

  1. values 下建立attrs.xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyButton">//声明的自定义属性集合
        <attr name="title" format="string" />
        <attr name="textSize" format="dimension" />
        <!--Reference可以是引用(的资源如@color或者@drawable)-->
        <attr name="background" format="reference|color" />
        <attr name="fraction" format="fraction" />
    </declare-styleable>
</resources>
  1. 在View的构造方法中获取 :尺寸得到的是px值整数值(四舍五入后的)
   public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        if (attrs != null) {
//            TypedArray 这种数据结构 存储了我们在xml中获取的值
//            从context通过获得    R.styleable.MyButton是我们定义的属性集合
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyButton);
//         获取键值:自定义Styleable的名字然后下划线属性
            background = typedArray.getDrawable(R.styleable.MyButton_background);
            textSize =  typedArray.getDimension(R.styleable.MyButton_textSize, 0);
            title = typedArray.getString(R.styleable.MyButton_title);
            fraction = typedArray.getFraction(R.styleable.MyButton_fraction, 0, 0, 0);
             typedArray.recycle(); //记得回收
        }
    }
  1. 关与OnMeasure :从MeasureSpec中获得测量模式,然后根据测量模式根据自己的需求设置宽高(得到的都是px) 设置宽高的函数是setMeasureDimension();
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout //这里的布局不能是ConstrainLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="net.hongqianfly.myview.MainActivity">
 <net.hongqianfly.myview.MyView
     android:layout_width="match_parent"
     android:layout_height="50dp"
     app:title="自定义view"
     app:gBackground="@color/colorAccent"
     app:textSize="50sp"
     android:background="@color/colorAccent"/>
</RelativeLayout>
@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        widthSize = MeasureSpec.getSize(widthMeasureSpec);
        heightSize = MeasureSpec.getSize(heightMeasureSpec);

        switch (widthMode) {
            case MeasureSpec.AT_MOST:
                break;
            case MeasureSpec.EXACTLY:
                widthSize = UiUtils.dip2px(mContext, 50);
                break;
            case MeasureSpec.UNSPECIFIED:
                break;
        }
        setMeasuredDimension(widthSize, heightSize);
    }

onDraw() 方法

画文字
- canvas.drawText("你好,中国!",100,60,mPaint);//以View的左上点为原点为,X轴向右为正,Y轴像下为正建立坐标系 (100,60) 指的是文字的左下角点的坐标
- canvas.drawText("你好,中国!",2,4,80,60,mPaint);//文字的开始坐标,结束坐标,以及左下角的坐标
- canvas.drawTextOnPath("1234567897545985445",path,0,0,mPaint);
参数 路径 ,距离路径开始点 x,y轴偏移量
画圆
canvas.drawCircle(100,100,30,mPaint); 以View的左上点为原点为,X轴向右为正,Y轴像下为正建立坐标系 (100,100) 指的是圆心坐标,30指的是半径
画线
canvas.drawLine(20,50,40,90,mPaint);//开始点坐标(20,50),结束点坐标(40,90) 
canvas.drawLines(new float[]{100,100,200,200,200,100,300,100}, p);
同时绘制多条线。 参数1:float数组:每四个一组为一条线。
        画虚线要用path画
        Path path = new Path();
        path.moveTo(0, 0);
        path.lineTo(500, 500);
        mPaint.setPathEffect(new DashPathEffect(new float[]{10, 15, 20, 25}, 0));
        canvas.drawPath(path, mPaint);
画矩形
RectF rectF = new RectF(0, 10, 400, 480); 前两个参数是左上角的坐标,后两个参数是右下角的坐标
Rect 的参数为int ,RectF的参数为float,RectF的精度更高一些,他们都是通过四个坐标参数来确定一个矩形的区域
RectF(float left,float top,fLoat right,float bottom)构造一个指定了4个参数的矩形.
RectF rectF = new RectF(0, 10, 400, 480);
canvas.drawRect(rectF,mPaint);

 //画圆角矩形  20,20为在X和Y轴上的半径 一般相等就好
    canvas.drawRoundRect(rectF,20,20,mPaint);
画椭圆
    RectF rectF = new RectF(0, 10, 400, 480);
    canvas.drawOval(rectF,mPaint);
   

画弧度

 RectF rectF = new RectF(0, 10, 400, 480); //先创建一个矩形,扇形与其相切,中心为矩形的中心点
20 初始角度 水平向右为0度,逆时针为正 
720 扫过的角度 
true 是否和中心点相连,true画出一个扇形 false 画出一个直线与圆弧相组成的图形
canvas.drawArc(rectF,20,60,true,mPaint);

多边形

用 Path来画
 path.addCircle(100,100,50, Path.Direction.CW);为 Path 中新增一个圆之后,调用 canvas.drawPath(path, paint) ,就能画一个圆出来。最后一个参数 dir 是画圆的路径的方向。路径方向有两种:顺时针 (CW clockwise) 和逆时针 (CCW counter-clockwise) 。对于普通情况,这个参数填 CW 还是填 CCW 没有影响。它只是在需要填充图形 (Paint.Style 为 FILL 或  FILL_AND_STROKE) ,并且图形出现自相交时,用于判断填充范围的。
  path.lineTo(100, 100); //参数是绝对坐标
  path.rLineTo(30,40);//参数是相对当前位置的相对坐标 (前缀 r 指的就是  relatively 「相对地」)。当前位置:所谓当前位置,即最后一次调用画 Path 的方法的终点位置。初始值为原点 (0, 0)
  path.arcTo(100, 100, 300, 300, -90, 90, false); 
  path.arcTo() 只用来画弧形而不画扇形,所以不再需要 useCenter 参数;而多出来的这个 forceMoveTo 参数的意思是,绘制是要「抬一下笔移动过去」,还是「直接拖着笔过去」,区别在于是否留下移动的痕迹。是否与之前连线
 path.addArc() 只是一个直接使用了 forceMoveTo = true 的简化版 arcTo() ;
  
  path.setFillType(Path.FillType.WINDING);//两个相交的圆设置全填充
  path.setFillType(Path.FillType.EVEN_ODD);//两圆相交不填充 两圆其余部分填充
   even-odd rule (奇偶原则):对于平面中的任意一点,向任意方向射出一条射线,这条射线和图形相交的次数(相交才算,相切不算哦)如果是奇数,则这个点被认为在图形内部,是要被涂色的区域;如果是偶数,则这个点被认为在图形外部,是不被涂色的区域。还以左右相交的双圆为例
   
   non-zero winding rule (非零环绕数原则):首先,它需要你图形中的所有线条都是有绘制方向的:同样是从平面中的点向任意方向射出一条射线,但计算规则不一样:以 0 为初始值,对于射线和图形的所有交点,遇到每个顺时针的交点(图形从射线的左边向右穿过)把结果加 1,遇到每个逆时针的交点(图形从射线的右边向左穿过)把结果减 1,最终把所有的交点都算上,得到的结果如果不是 0,则认为这个点在图形内部,是要被涂色的区域;如果是 0,则认为这个点在图形外部,是不被涂色的区域。
  

画点

canvas.drawPoint(60, 390, p);//画一个点  
canvas.drawPoints(new float[]{60,400,65,400,70,400}, p);//画多个点

画图片

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_arrow);
        RectF rectF = new RectF(0, 0, 80, 80);
        //第一个Rect为矩形的图片的显示大小,若为null,则显示整个大小
        //第二个Rect为矩形的显示区域
        canvas.drawBitmap(bitmap,null,rectF,mPaint);
        
        canvas.drawBitmap(bitmap,0,20,mpaint); //0,20图片左上角的坐标

drawColor()

类似的方法还有 drawRGB(int r, int g, int b) 和 drawARGB(int a, int r, int g, int b) ,它们和 drawColor(color) 只是使用方式不同,作用都是一样的
这类颜色填充方法一般用于在绘制之前设置底色,或者在绘制之后为界面设置半透明蒙版。

canvas

canvas .translate(100,50) //画布向X轴方向移动100,Y轴方向移动50
canvas.scale(2, 4);//画布x轴放大2倍,Y轴放大四倍 默认原点为左上角
canvas.scale(2, 4,100,100); 100,100为自定义的原点坐标
canvas.rotate(30);//左上角为中心点 顺时针为正
canvas.rotate(30,100,100); 以(100,100)为中心,旋转30度,顺时针方向为正方向 
Canvas保存和还原

Canvas提供了几个方法,让我们可以方便的对Canvas的状态进行更改和还原。
这些方法是:save()、restore()、restoreToCount(int saveCount)。

我们在对Canvas进行平移、旋转、放大等操作时候,可以调用save()方法,将当前修改过的Canvas状态进行保存,调用restore() 方法后,会将Canvas还原成最近的一个save() 的状态。

save()方法还会有一个返回值,我们也可以调用restoreToCount(int saveCount)方法,将这个返回值作为参数传递进去,就可以将Canvas还原成某一个特定的save()状态。

关于Paint

   setAntiAlias();            //设置画笔的锯齿效果

  setColor();                 //设置画笔的颜色

  setARGB();                 //设置画笔的A、R、G、B值

  setAlpha();                 //设置画笔的Alpha值

  setTextSize();             //设置字体的尺寸

   setDither(true);           //设置防抖动
   
   setStrokeWidth(float width) 设置线条宽度
   
   
  setStyle();                  //设置画笔的风格(空心或实心)
   - Paint.Style.FILL:填充内部
   - Paint.Style.FILL_AND_STROKE  :填充内部和描边
   - Paint.Style.STROKE  :描边

   setStrokeCap( Paint.Cap.BUTT );       // 线帽,即画的线条两端是否带有圆角,butt,无圆角
   
  setStrokeWidth();        //设置空心边框的宽度 画笔的线宽

  getColor();                  //获取画笔的颜色

获取res下面的文字和颜色

      String string = mContext.getString(R.string.app_name);
        int color = mContext.getResources().getColor(R.color.colorAccent);

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容