美文网首页
自定义开关

自定义开关

作者: GeekGray | 来源:发表于2018-10-02 22:45 被阅读9次

    阅读原文

    自定义开关

    自定义一个类继承View

    /**
     * 
     * @author: Hashub.NG
     * @description: 
     * @update: 2018年7月26日 上午8:59:25
     * 一个视图从创建到显示过程中的主要方法
     * //1.构造方法实例化类
     * //2.测量-measure(int,int)-->onMeasure();
     * 如果当前View是一个ViewGroup,还有义务测量孩子
     * 孩子有建议权
     * //3.指定位置-layout()-->onLayout();
     * 指定控件的位置,一般View不用写这个方法,ViewGroup的时候才需要,一般View不需要重写该方法
     * //4.绘制视图--draw()-->onDraw(canvas)
     * 根据上面两个方法参数,进入绘制
     */
    public class MyToggleButton extends View implements View.OnClickListener
    {
    
        private Bitmap backgroundBitmap;
        private Bitmap slidingBitmap;
        
        /**
         * 距离左边最大距离
         */
        private int slidLeftMax;
        private Paint paint;
        private int slideLeft;
        
        private float startX;
        private float lastX;
        
        private boolean isOpen=false;
        
        /**
         * 如果我们在布局文件使用该类,将会用这个构造方法实例该类,如果没有就崩溃
         * @param context
         * @param attrs
         */
        public MyToggleButton(Context context)
        {
            super(context);
            initView();
        }
    
        .......
    }
    

    实例化控件

    //创建两个Bitmap,这样才能绘制
    private Bitmap backgroundBitmap;
    private Bitmap slidingBitmap;
    
    private void initView()
        {
            paint=new Paint();
            paint.setAntiAlias(true);//设置抗锯齿,光滑
    
            backgroundBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);//从资源文件获取
            slidingBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);
            
            //背景宽度-遮盖部分的宽度
            slidLeftMax=backgroundBitmap.getWidth()-slidingBitmap.getWidth();
            
            setOnClickListener(this);//设置点击事件
        }
    

    重写onMeasure()测量方法

         /**
         * 视图的测量
         * @param widthMeasureSpec
         * @param heightMeasureSpec
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            
            //保存测量结果
            setMeasuredDimension(backgroundBitmap.getWidth(), backgroundBitmap.getHeight());
        }
    

    绘制

        /**
         * 绘制
         * @param canvas
         */
        @Override
        protected void onDraw(Canvas canvas)
        {
            //super.onDraw(canvas);
    
            canvas.drawBitmap(backgroundBitmap, 0, 0,paint);//绘制Bitmap
            canvas.drawBitmap(slidingBitmap, slideLeft,0, paint);
        }
    

    开关的点击事件

        /**
         * true:点击事件生效,滑动事件不生效
         * false:点击事件不生效,滑动事件生效
         */
        private boolean isEnableClick=true;
        
        @Override
        public void onClick(View v)
        {
            if(isEnableClick)
            {
                isOpen=!isOpen;
                flushView();
            }
        }
    
        private void flushView()
        {
            if(isOpen)
            {
                slideLeft=slidLeftMax;
            }
            else
            {
                slideLeft=0;
            }
            invalidate();//会导致onDraw()执行
        }
    

    开关的滑动事件(ACTION_DOWN,ACTION_MOVE,ACTION_UP)

    滑动在Y轴上无变化,记录X轴的坐标即可

    event.getX()和event.getRawX()的区别

        private float startX;//记录按下的横坐标
        private float lastX;//记录原始值,该值只记录一次
    
        @Override
        public boolean onTouchEvent(MotionEvent event)
        {
             super.onTouchEvent(event);//执行父类的方法
    
             switch (event.getAction())
            {
            case MotionEvent.ACTION_DOWN:
    
                 //1.记录按下的坐标
                lastX=startX=event.getX();
    
                isEnableClick=true;
                break;
    
            case MotionEvent.ACTION_MOVE:
    
                 //2.计算结束值
                float endX=event.getX();
    
                 //3.计算偏移量
                float distanceX=endX-startX;
    //          slideLeft = (int) (slideLeft + distanceX);//动态改变
                slideLeft+=distanceX;
    
                  //4.有可能越界,屏蔽非法值
                if(slideLeft<0)
                {
                    slideLeft=0;
                }
                else if(slideLeft>slidLeftMax)
                {
                    slideLeft=slidLeftMax;
                }
    
                //5.刷新
                invalidate();
                
                 //6.数据还原,startX重新赋值
                startX=event.getX();
                
                if(Math.abs(endX-lastX)>5)
                {
                    //滑动
                    isEnableClick=false;
                }
                break;
                
            case MotionEvent.ACTION_UP://根据距离松开回弹
                if(!isEnableClick)
                {
                    if(slideLeft>slidLeftMax/2)
                    {
                        //显示按钮开
                        isOpen=true;
                    }
                    else
                    {
                        isOpen=false;
                    }
                    flushView();
                }
                break;
            }
             return true;//处理触摸事件
        }
    

    解决事件的冲突

        /**
         * true:点击事件生效,滑动事件不生效
         * false:点击事件不生效,滑动事件生效
         */
        private boolean isEnableClick=true;
    

    最后的值-原始值如果大于5个px,就认为是滑动,点击事件不生效,滑动事件生效

    if(Math.abs(endX-lastX)>5)
                {
                    //滑动
                    isEnableClick=false;
                }

    相关文章

      网友评论

          本文标题:自定义开关

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