打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
自定义View示例

构造方法

  1. 创建一个 java 类,继承 View 父类。
  2. 重写3个构造方法

【示例】

public class MyView extends View {    
    public MyView(Context context) {
        this(context, null);    //调用本类第二个构造方法
    }
    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);      //调用本类第3个构造方法
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}

(注:修改前两个构造方法的目的是方便调用,无论调用哪个构造方法,其实最终调用的都是第3个构造方法。)

构造方法调用时机

第一个构造方法

    // 构造函数会在代码里面 new 的时候调用
    // MyView mv = new MyView(this);
    public MyView(Context context) {
        this(context, null);
    }

第二个构造方法

    // 在布局文件中添加控件时调用
    public MyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }
<!-- 路径:layout/activity_main.xml -->
    <com.example.viewproject.MyView
        app:text="ZZFan"
        app:textColor="@color/white"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

第三个构造方法=

    //布局文件中添加自定义属性,当使用 style 属性时调用该构造方法
    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
     <com.example.viewproject.MyView
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         style="@style/default" />

自定义属性

自定义控件需要使用自己定义的属性
一般在 res/values/ 新建 attrs.xml 文件添加自定义属性。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--自定义控件的属性也需要自定义-->

    <!--name:自定义控件的名字-->
    <declare-styleable name="MyView">
        <!--
            name:自定义属性的名称;
            format:格式 string 字符串
                    color 颜色
                    dimension 宽高,字体大小
                    integer 数字
                    reference 资源(drawable)
        -->
        <attr name="text" format="string" />
        <attr name="textColor" format="color" />
        <attr name="textSize" format="dimension" />
        <attr name="background" format="reference|color" />

        <!--枚举-->
        <attr name="inputType">
            <enum name="number" value="1" />
            <enum name="text" value="2" />
            <enum name="password" value="3" />
        </attr>
    </declare-styleable>
</resources>

然后在第三个构造方法中获取属性值

public class MyView extends View {

    private String mText;
    private int mTextSize = 15;
    private int mTextColor = Color.BLACK;

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //获取自定义属性
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyView);
        //获取文字
        mText = typedArray.getString(R.styleable.MyView_text);
        //获取颜色
        mTextColor = typedArray.getColor(R.styleable.MyView_textColor, mTextColor);
        //获取文字大小
        mTextSize = typedArray.getDimensionPixelSize(R.styleable.MyView_textSize, mTextSize);

        //回收
        typedArray.recycle();
    }
}

onMeasure()

    /**
     * 自定义View的测量方法
     * 布局的宽高由这个方法指定
     * @param widthMeasureSpec 宽
     * @param heightMeasureSpec 高
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //指定控件的宽高,需要测量
        int widthMode =  MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        /*
         * View测量模式
         * MeasureSpec.AT_MOST:在布局中指定为 wrap_content
         * MeasureSpec.EXACTLY:在布局中指定为确切的值(100dp)或 match_parent fill_parent
         * MeasureSpec.UNSPECIFIED:在布局中尽可能大,很少用到。
         *      ScrollView嵌套ListView使用时会有显示不全的问题,在测量子布局大小时会用到UNSPECIFIED
         */
        if (widthMode == MeasureSpec.AT_MOST) {
            //TODO
            //具体实现逻辑可以参考 ListView 中的 onMeasure() 方法
        }
    }

onDraw()


    /**
     * 用于绘制图像,包括画图,画文本
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //一般不在 onDraw() 中初始化 paint 对象
        Paint paint = new Paint();
        paint.setTextSize(100);
        //画文本
        //注意:x y 的值并不是文字的左上角,二十基于文字的基准线画的。
        canvas.drawText("HelloWorld", 200, 200, paint);


        //定义圆心位置,以及圆的大小
        float x = (getWidth() - getHeight() / 2) / 2;
        float y = getHeight() / 4;

        RectF oval = new RectF( x, y,
                getWidth() - x, getHeight() - y);
        //画弧
        /*
          @param oval 定义圆弧的形状和大小范围
          @param startAngle 设置圆弧是从哪个角度(哪个起始点)顺时针画的
          @param sweepAngle 圆弧扫过的角度
          @param useCenter If true, include the center of the oval in the arc, and close it if it is
                     being stroked. This will draw a wedge
                     (如果是 true 则图像为扇形,即绘制的图形是经过圆心的;如果是 false 则图像是半圆形。
          @param paint The paint used to draw the arc (画笔对象属性)
         */
        canvas.drawArc(oval, 360, 140, false, paint);

        //画圆
        /*
          @param cx 圆心 x 坐标
          @param cy 圆心 y 坐标
          @param radius 圆的半径
          @param paint 绘制时所使用的画笔
         */
        canvas.drawCircle(50, 50, 10, paint);
    }

onTouchEvent()


    /**
     * 处理跟用户交互的 Touch 事件,滑动滚动
     * @param event touch 事件分发、拦截
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //手指按下
                Log.d("onTouchEvent", "action down");

                break;
            case MotionEvent.ACTION_MOVE:
                //手指拖动
                Log.d("onTouchEvent", "action move");
                break;
            case MotionEvent.ACTION_UP:
                //手指抬起
                Log.d("onTouchEvent", "action up");
                break;
        }

        return super.onTouchEvent(event);
        /*
          return true; 这么写涉及到责任链模式,后续研究。
          主要是会调用一个 dispatchTouchEvent() 方法中的 while 循环,不断监听、分发 touch 事件。
          如果不设置成 true,那么响应一次 MotionEvent.ACTION_DOWN 之后就结束了,就不再回调 onTouchEvent 方法
         */
    }
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
onTouchEvent和onInterceptTouchEvent()
android初学者——自定义控件(继承View)
Android 中自定义属性(attr.xml,...
Android自定义View实现弹幕效果
android中
android自定义view 兑现TextView 中文粗体
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服