27 自定义View 和案例

  • 有时安卓提供的View不满足我们的需求时可以创建一个类继承View或其子类重写方法

    package com.qf.sxy.day28_customview.view;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.util.AttributeSet;
    import android.view.View;
    
    /**
     * Created by sxy on 2016/9/28.
     */
    public class MyTextView extends View {
        /**
         * 在逻辑代码中使用
         * @param context
         */
        public MyTextView(Context context) {
            super(context);
        }
    
        /**
         * 布局文件中使用    note:布局中使用必须有俩个参数
         * @param context
         * @param attrs   布局中设置的属性
         */
        public MyTextView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        /**
         * @param context
         * @param attrs 布局中设置的属性
         * @param defStyleAttr 指定样式资源
         */
        public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
    
        /**
         * 绘制的方法
         * @param canvas   画布
         */
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            //创建画笔对象
            Paint paint =  new Paint();
            paint.setColor(Color.BLUE);
    //        paint.setColor(0xff00);//0x 红  绿 蓝
            paint.setStrokeWidth(3);//设置画笔粗细
            paint.setAntiAlias(true);//抗锯齿 边缘柔和
            paint.setTextSize(30);//设置文字大小
            paint.setStyle(Paint.Style.STROKE);//设置样式  空心
            /**
             * 画直线
             * 参数1:x轴起始位置
             * 参数2:y轴起始位置
             * 参数3:x轴终止位置
             * 参数4:y轴终止位置
             * 参数5:画笔对象
             */
            canvas.drawLine(0,0,getWidth(),getHeight(),paint);
    
            /**
             * 画圆
             * 参数1,2:圆心
             * 参数3:半径
             * 参数4:画笔
             */
            canvas.drawCircle(200,200,100,paint);
    
            /**
             * 画文字
             * 参数1:内容
             * 参数2,3:起始位置
             * 参数4:画笔
             */
            canvas.drawText("国庆快乐",0,100,paint);
    
            /**
             * 画图片
             */
           // canvas.drawBitmap();
            /**
             * 画矩阵
             */
           // canvas.clipRect()
    
            //....
        }
    }
    
  • 在使用此自定义View的时候在布局文件 写完整的包名类名

    •   <!--
          使用自定义View   包名+类名
          -->
          <com.qf.sxy.day28_customview.view.MyTextView
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              />
  • 如果我们想在布局文件中设置属性的话 那么可以按一下步骤

    • 在valus文件夹新建一个resources文件
    • <?xml version="1.0" encoding="utf-8"?>
      <resources>
          <!--
          circleColor  圆的颜色
          sweepColor   扫描的颜色
          startAngle 起始角度
          sweepAngle 扫描角度
          sweepStep 每次扫描的步数
          -->
          <declare-styleable name="ProgressView">
              <attr name="circleColor" format="color|reference"></attr>
              <attr name="sweepColor" format="color|reference"></attr>
              <attr name="startAngle" format="integer|reference"></attr>
              <attr name="sweepAngle" format="integer|reference"></attr>
              <attr name="sweepStep" format="integer|reference"></attr>
          </declare-styleable>
      </resources>
    • 赋值方法

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout 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"
          xmlns:app="http://schemas.android.com/apk/res-auto"
          android:orientation="vertical"
          tools:context="com.qf.sxy.customview3.MainActivity">
      
          <com.qf.sxy.customview3.widget.ProgressView
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              app:circleColor="#00ff00"
              app:sweepColor="#0000ff"
              app:sweepStep="10"
              app:sweepAngle="0"
              app:startAngle="0"
               />
          <com.qf.sxy.customview3.widget.ProgressView
              android:layout_width="200dp"
              android:layout_height="200dp"
              app:circleColor="#0000ff"
              app:sweepColor="#ff00ff"
              app:sweepStep="2"
              app:startAngle="-90"
               />
          <com.qf.sxy.customview3.widget.ProgressView
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              app:circleColor="#00ffff"
              app:sweepColor="#005644"
              app:sweepStep="20"
              app:startAngle="180"
               />
      </LinearLayout>
      
    • 获取属性值

        public ProgressView(Context context) {
                      this(context,null);
                  }
      
                  public ProgressView(Context context, AttributeSet attrs) {
                      super(context, attrs);
                      //获取布局中属性
                      TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.ProgressView);
                      if(array!=null){
                          circleColor = array.getColor(R.styleable.ProgressView_circleColor,Color.BLUE);
                          sweepColor = array.getColor(R.styleable.ProgressView_sweepColor,Color.RED);
                          startAngle = array.getInteger(R.styleable.ProgressView_startAngle,-90);
                          sweepStep = array.getInteger(R.styleable.ProgressView_sweepStep,1);
                      }
      
                  }

具体案例一

一个最基础的案例 继承一个View画一个圆等
这里写图片描述

  • 重写View文件MyTextView.java
package com.qf.sxy.day28_customview.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by sxy on 2016/9/28.
 */
public class MyTextView extends View {
    /**
     * 在逻辑代码中使用
     * @param context
     */
    public MyTextView(Context context) {
        super(context);
    }

    /**
     * 布局文件中使用    note:布局中使用必须有俩个参数
     * @param context
     * @param attrs   布局中设置的属性
     */
    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * @param context
     * @param attrs 布局中设置的属性
     * @param defStyleAttr 指定样式资源
     */
    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    /**
     * 绘制的方法
     * @param canvas   画布
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //创建画笔对象
        Paint paint =  new Paint();
        paint.setColor(Color.BLUE);
//        paint.setColor(0xff00);//0x 红  绿 蓝
        paint.setStrokeWidth(3);//设置画笔粗细
        paint.setAntiAlias(true);//抗锯齿 边缘柔和
        paint.setTextSize(30);//设置文字大小
        paint.setStyle(Paint.Style.STROKE);//设置样式  空心
        /**
         * 画直线
         * 参数1:x轴起始位置
         * 参数2:y轴起始位置
         * 参数3:x轴终止位置
         * 参数4:y轴终止位置
         * 参数5:画笔对象
         */
        canvas.drawLine(0,0,getWidth(),getHeight(),paint);

        /**
         * 画圆
         * 参数1,2:圆心
         * 参数3:半径
         * 参数4:画笔
         */
        canvas.drawCircle(200,200,100,paint);

        /**
         * 画文字
         * 参数1:内容
         * 参数2,3:起始位置
         * 参数4:画笔
         */
        canvas.drawText("国庆快乐",0,100,paint);

        /**
         * 画图片
         */
       // canvas.drawBitmap();
        /**
         * 画矩阵
         */
       // canvas.clipRect()

        //....
    }
}

布局文件activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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.qf.sxy.day28_customview.MainActivity">

<!--
使用自定义View   包名+类名
-->
<com.qf.sxy.day28_customview.view.MyTextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />
</RelativeLayout>

具体案例二

说明
展示如何设置属性 然后在布局文件里面赋值 和在重写类获取对应属性值

这里写图片描述

(重写View方法的类)MyTextView.java

package com.qf.sxy.customview02.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;

import com.qf.sxy.customview02.R;

/**
 * Created by sxy on 2016/9/28.
 */
public class MyTextView extends View {

    TextView tv;

    private Paint mPaint;

    private String mText="哈哈";
    public MyTextView(Context context) {
        super(context);
        initPain();
    }

    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPain();

        //获取布局资源中的属性
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyTextView);

        //获取文本内容
        CharSequence ch = array.getText(R.styleable.MyTextView_text);
        if(ch!=null&&!"".equals(ch)){
            setText(ch.toString());
        }
        //获取文本颜色
        int textColor = array.getColor(R.styleable.MyTextView_textColor,Color.BLACK);
        settextColor(textColor);

        //获取字体大小
        int textSize = (int)(array.getDimension(R.styleable.MyTextView_textSize,30));
        setTextSize(textSize);


    }


    //设置字体大小
    private void setTextSize(int textSize) {
        mPaint.setTextSize(textSize);
        requestLayout();//重新绘制画布 会
        invalidate();//进行刷新(重新获取数据)
    }


    //设置文本颜色
    public void settextColor(int textColor) {
        mPaint.setColor(textColor);
        requestLayout();//重新绘制画布
        invalidate();//进行刷新(重新获取数据)
    }
    //给文本设置内容
    private void setText(String str) {
        mText = str;
        //onMeasure只会重新调用次方
        requestLayout();//重新绘制画布
        //重新调用ondraw方法 和上诉方法正好相反
        invalidate();//进行刷新(重新获取数据)
    }

    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPain();
    }


    //初始化画笔对象
    public void initPain() {
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setAntiAlias(true);
        mPaint.setTextSize(30);
        //设置文字的内边距
        setPadding(10,10,10,10);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //给画布设置颜色
        canvas.drawColor(Color.GREEN);

        canvas.drawText(mText,getPaddingLeft(),getPaddingTop()-mPaint.ascent(),mPaint);
    }

    /**
     * 测量控件大小
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

//        //得到设置的模式
//        int wMode = MeasureSpec.getMode(widthMeasureSpec);
//        //获取父布局的宽高/50dp
//        int wSize = MeasureSpec.getSize(widthMeasureSpec);
//
//        /**
//         * MeasureSpec.UNSPECIFIED:Adapter View用到  未设定尺寸
//         * MeasureSpec.AT_MOST:wrap_content  根据里面内容变化而变化
//         * MeasureSpec.EXACTLY:match_parent/50dp   精准的值
//         */
//
//        if(wMode == MeasureSpec.AT_MOST){//wrap_content  根据里面内容变化而变化
//            //获取宽  计算
//
//        }else if(wMode == MeasureSpec.EXACTLY){ //match_parent/50dp   精准的值
//            //wSize
//        }

        //设定最终的宽和高
       setMeasuredDimension(Measure(widthMeasureSpec,1),Measure(heightMeasureSpec,2));
    }


    //进行测量
    public int Measure(int Spec ,int type){

        int result=0;//返回的值

        int mode = MeasureSpec.getMode(Spec);
        int size = MeasureSpec.getSize(Spec);

        if(mode == MeasureSpec.AT_MOST){//wrap_content  根据里面内容变化而变化
            //计算
            if(type==1){//获取宽     左右内边距+文字宽
                result = (int)(getPaddingLeft()+getPaddingRight()+mPaint.measureText(mText));
            }else if(type==2){//获取高
                result = (int)(getPaddingTop()+getPaddingBottom()+mPaint.descent()-mPaint.ascent());
            }

        }else if(mode == MeasureSpec.EXACTLY){ //match_parent/50dp   精准的值
            //wSize
            result = size;
        }

        return result;
    }



}

设置属性文件attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!--
      <declare-styleable name="样式名称">
      name ="名称" format="类型"
      string  字符串
      reference  引用的类型  R.string.xxx
      dimension 尺寸
      color 颜色
        <attr name="text" format="string|reference"></attr>
    </declare-styleable>

    -->
    <declare-styleable name="MyTextView">
        <attr name="text" format="string|reference"></attr>
        <!--dimension可以在此属性写 XXXDP或者XXXDIP-->
        <attr name="textSize" format="dimension|reference"></attr>
        <attr name="textColor" format="color|reference"></attr>
    </declare-styleable>
</resources>

activity_main.xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.qf.sxy.customview02.MainActivity">

    <!--
    命名空间  引用资源的
     xmlns:app="http://schemas.android.com/apk/res-auto"

      xmlns:app="http://schemas.android.com/apk/包名"
    -->

    <com.qf.sxy.customview02.widget.MyTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:text="国庆快乐"
        app:textSize="20sp"
        app:textColor="#ff00ff"
       />
</RelativeLayout>

案例三

说明 在界面画一个圆 然后让其一直旋转 360APP的雷达效果

这里写图片描述

ProgressView.java(重写View方法)

package com.qf.sxy.customview3.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

import com.qf.sxy.customview3.R;

/**
 * Created by sxy on 2016/9/28.
 */
public class ProgressView extends View {

    private int circleColor = Color.BLUE;//设置颜色

    private int startAngle = -90;//开始的角度
    private int sweepAngle = 0;//扫描的角度
    private int sweepStep = 5;//每次扫描走多少
    private int sweepColor = Color.RED;

    //wrap_content  设定宽高  100
    int sweepWith =100;
    int sweepHeight =100;

    public ProgressView(Context context) {
        this(context,null);
    }

    public ProgressView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //获取布局中属性
        TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.ProgressView);
        if(array!=null){
            circleColor = array.getColor(R.styleable.ProgressView_circleColor,Color.BLUE);
            sweepColor = array.getColor(R.styleable.ProgressView_sweepColor,Color.RED);
            startAngle = array.getInteger(R.styleable.ProgressView_startAngle,-90);
            sweepStep = array.getInteger(R.styleable.ProgressView_sweepStep,1);
        }

    }


    /**
     * 绘制
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(circleColor);
        paint.setAntiAlias(true);

        //绘制圆  控件的一半
        canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2,paint);

        //重新设置画笔颜色
        paint.setColor(sweepColor);
        //绘制的扇形
        canvas.drawArc(new RectF(0,0,getWidth(),getHeight()),startAngle,sweepAngle,true,paint);
        sweepAngle += sweepStep;//扫描角度等于 走的和
        sweepAngle= sweepAngle>360?0:sweepAngle;//是否跑了一圈
        invalidate();//刷新数据
    }

    /**
     * 测量
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);


        int wMode = MeasureSpec.getMode(widthMeasureSpec);
        int hMode = MeasureSpec.getMode(heightMeasureSpec);

        int wSize = MeasureSpec.getSize(widthMeasureSpec);
        int hSize = MeasureSpec.getSize(heightMeasureSpec);


        switch (wMode){
            case MeasureSpec.AT_MOST:
               // wSize = sweepWith;
                wSize = hSize = sweepHeight;

                break;
            case MeasureSpec.EXACTLY:
                wSize = hSize = Math.min(wSize,hSize);
                break;
        }
        //设置最终的宽高
        setMeasuredDimension(wSize,hSize);

    }
}

属性文件attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--
    circleColor  圆的颜色
    sweepColor   扫描的颜色
    startAngle 起始角度
    sweepAngle 扫描角度
    sweepStep 每次扫描的步数
    -->
    <declare-styleable name="ProgressView">
        <attr name="circleColor" format="color|reference"></attr>
        <attr name="sweepColor" format="color|reference"></attr>
        <attr name="startAngle" format="integer|reference"></attr>
        <attr name="sweepAngle" format="integer|reference"></attr>
        <attr name="sweepStep" format="integer|reference"></attr>
    </declare-styleable>
</resources>

布局文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    tools:context="com.qf.sxy.customview3.MainActivity">

    <com.qf.sxy.customview3.widget.ProgressView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:circleColor="#00ff00"
        app:sweepColor="#0000ff"
        app:sweepStep="10"
        app:sweepAngle="0"
        app:startAngle="0"
         />
    <com.qf.sxy.customview3.widget.ProgressView
        android:layout_width="200dp"
        android:layout_height="200dp"
        app:circleColor="#0000ff"
        app:sweepColor="#ff00ff"
        app:sweepStep="2"
        app:startAngle="-90"
         />
    <com.qf.sxy.customview3.widget.ProgressView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:circleColor="#00ffff"
        app:sweepColor="#005644"
        app:sweepStep="20"
        app:startAngle="180"
         />
</LinearLayout>

案例四

继承View 并实现监听方法 当用户点击时View中的数字+1
这里写图片描述

重写View的类CountView.java

package com.qf.sxy.customview04;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by sxy on 2016/9/28.
 */
public class CountView extends View implements View.OnClickListener{

    private Paint mPaint;
    private int count =0;

    public CountView(Context context) {
        this(context,null);
    }

    public CountView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public CountView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //初始化化画笔对象
        initPaint();
        //监听事件
        setOnClickListener(this);
    }

    private void initPaint(){
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.RED);
        mPaint.setTextSize(300);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //获取当前的数字字符串
        String countStr =String.valueOf(count);
        Rect rect = new Rect();
        //获取文字区域
        mPaint.getTextBounds(countStr,0,countStr.length(),rect);
        int strWith =  rect.width();
        int strHeight = rect.height();

        canvas.drawText(countStr,getWidth()/2-strWith/2,getHeight()/2+strHeight/2,mPaint);
    }


    //点击事件的监听
    @Override
    public void onClick(View v) {
        count++;
        invalidate();//刷新
    }
}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.qf.sxy.customview04.MainActivity">

    <com.qf.sxy.customview04.CountView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

案例五

说明 View上有一个点 当用户点击或者移动时小点变色并且跟随移动

这里写图片描述

重写View的类BallView.java

package com.qf.sxy.customview05.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.util.Random;

/**
 * Created by sxy on 2016/9/28.
 */
public class BallView extends View {

    private Paint mPaint;
    private int cx = 50,cy=50,radius = 20;//圆心x  圆心y  半径

    //小球颜色随机改变
    private int[] colors = {Color.BLACK,Color.BLUE,Color.DKGRAY,Color.GREEN,Color.RED,Color.YELLOW};


    private int pWith = 100,pHeight =100;
    public BallView(Context context) {
        this(context,null);
    }

    public BallView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public BallView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //初始化画笔对象
        initPaint();
    }

    private void initPaint(){
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.RED);
    }

    //绘制  小球
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //是否出界
        isOutSide();

        //随机获取颜色
        getBallColor();

        //绘制一个小球
        canvas.drawCircle(cx,cy,radius,mPaint);
    }

    private void isOutSide() {

        if(cx<radius){//左
            cx = radius;
        }
        if(cx>pWith-radius){//右
            cx = pWith-radius;
        }
        if(cy<radius){//上
            cy = radius;
        }
        if(cy>pHeight-radius){//下
            cy = pHeight-radius;
        }

    }


    private void getBallColor() {
        Random r = new Random();
        int color = r.nextInt(colors.length);
        mPaint.setColor(colors[color]);

    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN://按下事件
                cx = (int)event.getX();
                cy = (int)event.getY();
                invalidate();//刷新
                break;
            case MotionEvent.ACTION_MOVE://移动事件
                cx = (int)event.getX();
                cy = (int)event.getY();
                invalidate();//刷新
                break;
            case MotionEvent.ACTION_UP://抬起的事件
                cx = (int)event.getX();
                cy = (int)event.getY();
                invalidate();//刷新
                break;
        }
        //消费事件 不然会有问题
        return true;
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        pWith = MeasureSpec.getSize(widthMeasureSpec);
        pHeight = MeasureSpec.getSize(heightMeasureSpec);
    }
}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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.qf.sxy.customview05.MainActivity">

    <com.qf.sxy.customview05.widget.BallView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</RelativeLayout>

案例6

说明 重写EditText 并监听文本改变事件 如果有字就在文本框右侧改变图片

这里写图片描述

MyEditText.java

package com.qf.sxy.customview06.widget;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.widget.EditText;

import com.qf.sxy.customview06.R;

/**
 * Created by sxy on 2016/9/28.
 */
public class MyEditText extends EditText {

    Drawable drawable1;
    Drawable drawable2;
    public MyEditText(Context context) {
        this(context,null);
    }

    public MyEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        changeBitmap();
    }

    public MyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //根据文本输入 修改图片
       // changeBitmap();
    }


    public void changeBitmap(){


        addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                //修改图片
                setBitmap();
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });


        setBitmap();
    }

    //设置图片
    public void setBitmap(){
         drawable1 =getResources().getDrawable(R.mipmap.ic_launcher);
         drawable2 =getResources().getDrawable(R.mipmap.qq);

        if(length()>0){//设置一种图片
//            setFocusable(true);
            //左上右下
            setCompoundDrawablesWithIntrinsicBounds(null,null,drawable1,null);

        }else{//设置另一种图片
           // setFocusable(true);
//左上右下
            setCompoundDrawablesWithIntrinsicBounds(null,null,drawable2,null);
        }

    }


}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context="com.qf.sxy.customview06.MainActivity">

    <com.qf.sxy.customview06.widget.MyEditText
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:enabled="true"

        android:hint="请输入姓名" />
    <com.qf.sxy.customview06.widget.MyEditText
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:hint="请输入密码"
       />
</LinearLayout>

案例7

说明 继承EditText 设置一张背景图 并且划线 让其想一个笔记本

这里写图片描述

MyNoteView.java

package com.qf.sxy.customview07.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.EditText;

import com.qf.sxy.customview07.R;

/**
 * Created by sxy on 2016/9/28.
 */
public class MyNoteView extends EditText {


    private int lineSpace = 50;//行间距
    private Paint mPaint ;
    private int linePadding = 60;//设置内边距
    private int lineColor = Color.RED;

    public MyNoteView(Context context) {
        super(context);
    }

    public MyNoteView(Context context, AttributeSet attrs) {
        super(context, attrs);

        //初始化画笔对象
        initPaint();


        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyNoteView);
        if(array!=null){
            lineColor = array.getColor(R.styleable.MyNoteView_lineColor,Color.RED);
            linePadding = array.getInteger(R.styleable.MyNoteView_linePadding,60);
            lineSpace = array.getInteger(R.styleable.MyNoteView_lineSpace,60);
        }

        mPaint.setColor(lineColor);

        //设置行间距  参数1:间距  参数2:倍数
        setLineSpacing(lineSpace,1);
        //设置整个的内边距
        setPadding(linePadding,0,linePadding,0);
        //文字从顶部开始
        setGravity(Gravity.TOP);
    }


    public void initPaint(){
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.RED);
    }

    //绘制线
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //获取View的高度
        int height = getHeight();
        //获取每一行的高度
        int lineHeight = getLineHeight();
        //得到总的线的数量
        int lineNum = height/lineHeight;

        for(int i=0;i<lineNum;i++){
            canvas.drawLine(linePadding,(i+1)*lineHeight,getWidth()-linePadding,(i+1)*lineHeight,mPaint);
        }

        //获取文本行数
        int linesCount = getLineCount();
        //画多余的部分
        for(int i = lineNum;i<linesCount;i++ ){
            canvas.drawLine(linePadding,i*lineHeight,getWidth()-linePadding,i*lineHeight,mPaint);
        }

    }
}

属性文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyNoteView">
        <attr name="lineSpace" format="integer|reference"></attr>
        <attr name="linePadding" format="integer|reference"></attr>
        <attr name="lineColor" format="color|reference"></attr>
    </declare-styleable>
</resources>

布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context="com.qf.sxy.customview07.MainActivity">

    <com.qf.sxy.customview07.widget.MyNoteView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@mipmap/background"
        app:lineColor="#0000ff"
        app:linePadding="100"
        app:lineSpace="30"
        />
</RelativeLayout>
原文地址:https://www.cnblogs.com/muyuge/p/6152169.html