美文网首页
何止学习Android自定义view

何止学习Android自定义view

作者: 何止搬砖工 | 来源:发表于2020-07-08 23:21 被阅读0次

    View绘制流程
    View的绘制基本由measure()、layout()、draw()这个三个函数完成。

    一、自定义view类型

    1.继承View的自定义view
    在没有现成的View,需要自己实现的时候,就使用自定义View,一般继承自View,SurfaceView或其他的View,不包含子View。

    2.继承ViewGroup的自定义view
    继承ViewGroup的自定义view一般是利用现有的组件根据特定的布局方式来组成新的组件,大多继承自ViewGroup或各种Layout,包含有子View。

    二、举个栗子

    自定义view
    先上图:主体是一个正方形,中间区域为文字。四个角为圆形,并且为四个圆形区域添加点击事件监听器。


    image.png

    结合代码说明:
    1.新建HezhiView类,继承View,实现构造方法,并且初始化画笔等(其中两个参数的构造法是在xml布局初始化会用到)

       public HezhiView(Context context) {
            super(context);
            init();
        }
    
        public HezhiView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init();
    
        }
    
        public HezhiView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
    
        private void init() {
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setStrokeWidth(5);
            mPaint.setColor(Color.WHITE);
            mPaint.setStyle(Paint.Style.STROKE);
            mPath = new Path();
        }
    

    2.重写onDraw方法,执行画正方形、画圆、画文字操作。

       @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawColor(getResources().getColor(R.color.colorPrimary));
            centerX = getWidth() / 2;
            centerY = getHeight() / 2;
            drawSquare(canvas);
            drawCircle(canvas);
            drawText(canvas);
    
        }
    
        private void drawSquare(Canvas canvas) {
            mPath.moveTo(centerX - 200, centerY - 200);
            mPath.lineTo(centerX - 200, centerY + 200);
            mPath.lineTo(centerX + 200, centerY + 200);
            mPath.lineTo(centerX + 200, centerY - 200);
            mPath.close();
            canvas.drawPath(mPath, mPaint);
        }
    
        private void drawCircle(Canvas canvas) {
            canvas.drawCircle(centerX - 200, centerY - 200,50,mPaint);
            canvas.drawCircle(centerX - 200, centerY + 200,50,mPaint);
            canvas.drawCircle(centerX + 200, centerY + 200,50,mPaint);
            canvas.drawCircle(centerX + 200, centerY - 200,50,mPaint);
        }
    
        private void drawText(Canvas canvas) {
            Paint.FontMetrics fm = mPaint.getFontMetrics();//用于计算文字的高度
            String text = "何止";
            mPaint.setTextSize(100);
            canvas.drawText(text, centerX - mPaint.measureText(text) / 2,
                    (centerY + (int) Math.ceil(fm.descent - fm.ascent) / 2), mPaint);
        }
    

    3、为四个圆形添加事件监听器,重写onTouchEvent方法。
    通过坐标判断是否在圆形区域内,进行回调。

    
        public boolean onTouchEvent(MotionEvent event){
    
            int x = (int) event.getX();
            int y = (int) event.getY();
    
            if (event.getAction() == MotionEvent.ACTION_UP){
                if (isInner(x,y,centerX - 200,centerY - 200,50)){
                    if (null != this.listenr){
                        this.listenr.callOnClick(0);
                    }
                    return true;
                }
                if (isInner(x,y,centerX - 200,centerY + 200,50)){
                    if (null != this.listenr){
                        this.listenr.callOnClick(1);
                    }
                    return true;
                }
                if (isInner(x,y,centerX + 200,centerY + 200,50)){
                    if (null != this.listenr){
                        this.listenr.callOnClick(2);
                    }
                    return true;
                }
                if (isInner(x,y,centerX + 200,centerY - 200,50)){
                    if (null != this.listenr){
                        this.listenr.callOnClick(3);
                    }
                    return true;
                }
                return false;
            }else{
                return true;
            }
    
        }
    
        private boolean isInner(int x,int y ,int rx,int ry,int r){
           return Math.pow(x-rx,2) + Math.pow(y-ry,2) <= Math.pow(r,2);
        }
    
        public void setListenr(Listenr listenr){
            this.listenr = listenr;
        }
    
        public interface Listenr{
            void callOnClick(int index);
        }
    

    注意:在onTouchEvent方法内,需要判断MotionEvent的类型,点击事件会先执行MotionEvent.ACTION_DOWN。若事件没有被消费,则不再执行MotionEvent.ACTION_UP事件。因此,在MotionEvent.ACTION_DOWN时需要return true。这涉及到事件分发机制,下次学习。

    自定义属性
    在values文件夹中创建attrs.xml文件,设置相关属性

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="HezhiView"> // 自定义属性集合
            <attr name="hezhi_color" format="color" />
            <attr name="hezhi_width" format="dimension" />
            <attr name="hezhi_height" format="dimension" />
        </declare-styleable>
    </resources>
    

    自定义属性应用
    需要引入xmlns:app="http://schemas.android.com/apk/res-auto"命名空间

        <com.example.customer.view.PentagonView.HezhiView
            android:id="@+id/hezhi_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@color/colorAccent"
            android:padding="10dp"
            app:hezhi_color="#d0d0d0"
            app:hezhi_height="300dp"
            app:hezhi_width="300dp">
    
        </com.example.customer.view.PentagonView.HezhiView>
    

    重写onMeasure,对view进行测量

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
            int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
            int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
    
            int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
            int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
    
            if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
                setMeasuredDimension(mWidth, mHeight);
            } else if (widthSpecMode == MeasureSpec.AT_MOST) {
                setMeasuredDimension(mWidth, heightSpecSize);
            } else if (heightSpecMode == MeasureSpec.AT_MOST) {
                setMeasuredDimension(widthSpecSize, mHeight);
            }
        }
    

    最终效果


    image.png

    相关文章

      网友评论

          本文标题:何止学习Android自定义view

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