本文实例为大家分享了Android自定义View实现遥控器按钮的具体代码,供大家参考,具体内容如下

效果图:

原理:

  • onSizeChanged拿到控件宽高,进行path和region的计算(此处,path和region的坐标值都是以viewWidth/2,viewHeight/2为坐标原点进行计算的)
  • 画布平移,绘制5个path
  • 点击事件,判断是否处于相应的region区域内,进行控件的重绘
  • 点击事件motionEvent的原始坐标(getX和getY),是以viewParent的左上角为坐标原点的,需要经过matrix转换成以控件中心点为原点的坐标体系。

Region区域,paint的style设置为stroke模式,遍历绘制

mPaint.setColor(Color.RED);
RegionIterator iterator = new RegionIterator(topRegion);
 Rect r = new Rect();
 while (iterator.next(r)) {
      canvas.drawRect(r, mPaint);
 }

源码:

public class RemoteControlMenu extends View {

    private int mWidth;
    private int mHeight;

    private RectF bigRectF;
    private int bigRadius;
    private RectF smallRectF;
    private int smallRadius;
    private int padding = 20;
    private int sweepAngel = 80;
    private int offsetAngel;

    @TouchArea
    private int mTouchArea = TouchArea.INVALID;

    private Paint mPaint;
    private Region topRegion, bottomRegion, leftRegion, rightRegion, centerRegion, globalRegion;
    private Path topPath, bottomPath, leftPath, rightPath, centerPath, selectedPath;

    Matrix mMapMatrix;

    private int unselectedColor = 0xff4c5165;
    private int selectedColor = 0xffdd9181;

    private boolean isSelected = false;


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

    public RemoteControlMenu(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RemoteControlMenu(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(4);
        mPaint.setColor(unselectedColor);

        offsetAngel = (360 - sweepAngel * 4) / 4;
        bigRectF = new RectF();
        smallRectF = new RectF();

        topRegion = new Region();
        bottomRegion = new Region();
        leftRegion = new Region();
        rightRegion = new Region();
        centerRegion = new Region();
        globalRegion = new Region();
        topPath = new Path();
        bottomPath = new Path();
        leftPath = new Path();
        rightPath = new Path();
        centerPath = new Path();
        mMapMatrix = new Matrix();
    }

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({TouchArea.LEFT, TouchArea.TOP, TouchArea.RIGHT, TouchArea.BOTTOM,
            TouchArea.CENTER, TouchArea.INVALID})
    private @interface TouchArea {
        int LEFT = 1;
        int TOP = 2;
        int RIGHT = 3;
        int BOTTOM = 4;
        int CENTER = 5;
        int INVALID = 0;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float[] pts = new float[2];
        pts[0] = event.getX();
        pts[1] = event.getY();
        Log.d("zhen", "原始触摸位置:"   Arrays.toString(pts)   " mMapMatrix: "   mMapMatrix);
        mMapMatrix.mapPoints(pts);

        int x = (int) pts[0];
        int y = (int) pts[1];
        Log.w("zhen", "转换后的触摸位置:"   Arrays.toString(pts)   " mMapMatrix: "   mMapMatrix);
        int touchArea = TouchArea.INVALID;
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                if (leftRegion.contains(x, y)) {
                    touchArea = TouchArea.LEFT;
                }
                if (topRegion.contains(x, y)) {
                    touchArea = TouchArea.TOP;
                }
                if (rightRegion.contains(x, y)) {
                    touchArea = TouchArea.RIGHT;
                }
                if (bottomRegion.contains(x, y)) {
                    touchArea = TouchArea.BOTTOM;
                }
                if (centerRegion.contains(x, y)) {
                    touchArea = TouchArea.CENTER;
                }
                if (touchArea == TouchArea.INVALID) {
                    mTouchArea = touchArea;
                    Log.w("zhen", "点击outside");
                } else {
                    if (mTouchArea == touchArea) {
                        //取消选中
                        isSelected = false;
                        mTouchArea = TouchArea.INVALID;
                    } else {
                        //选中
                        isSelected = true;
                        mTouchArea = touchArea;
                    }
                    Log.w("zhen", "按钮状态 mTouchArea "   mTouchArea   " isSelected: "   isSelected);
                    if (mListener != null) {
                        mListener.onMenuClicked(mTouchArea, isSelected);
                    }
                    invalidate();
                }
                break;
        }

        return true;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
        //大圆
        bigRadius = (Math.min(mWidth, mHeight) - 250) / 2;
        bigRectF.set(-bigRadius, -bigRadius, bigRadius, bigRadius);
        //小圆
        smallRadius = (bigRadius - padding) / 2;
        smallRectF.set(-smallRadius - padding, -smallRadius - padding,
                smallRadius   padding, smallRadius   padding);

        mMapMatrix.reset();
        globalRegion.set(-mWidth / 2, -mHeight / 2, mWidth / 2, mHeight / 2);

        centerPath.addCircle(0, 0, smallRadius, Path.Direction.CW);
        centerRegion.setPath(centerPath, globalRegion);

        float startAngel = -sweepAngel / 2f;
        rightPath.addArc(bigRectF, startAngel, sweepAngel   4);
        startAngel  = sweepAngel;
        rightPath.arcTo(smallRectF, startAngel, -sweepAngel);
        rightPath.close();
        rightRegion.setPath(rightPath, globalRegion);

        startAngel  = offsetAngel;
        bottomPath.addArc(bigRectF, startAngel, sweepAngel   4);
        startAngel  = sweepAngel;
        bottomPath.arcTo(smallRectF, startAngel, -sweepAngel);
        bottomPath.close();
        bottomRegion.setPath(bottomPath, globalRegion);

        startAngel  = offsetAngel;
        leftPath.addArc(bigRectF, startAngel, sweepAngel   4);
        startAngel  = sweepAngel;
        leftPath.arcTo(smallRectF, startAngel, -sweepAngel);
        leftPath.close();
        leftRegion.setPath(leftPath, globalRegion);

        startAngel  = offsetAngel;
        topPath.addArc(bigRectF, startAngel, sweepAngel   4);
        startAngel  = sweepAngel;
        topPath.arcTo(smallRectF, startAngel, -sweepAngel);
        topPath.close();
        topRegion.setPath(topPath, globalRegion);
        Log.d("zhen", "globalRegion: "   globalRegion);
        Log.d("zhen", "globalRegion: "   globalRegion);
        Log.d("zhen", "leftRegion: "   leftRegion);
        Log.d("zhen", "topRegion: "   topRegion);
        Log.d("zhen", "rightRegion: "   rightRegion);
        Log.d("zhen", "bottomRegion: "   bottomRegion);
        Log.d("zhen", "centerRegion: "   centerRegion);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(mWidth / 2, mHeight / 2);
        // 获取测量矩阵(逆矩阵)
        if (mMapMatrix.isIdentity()) {
            canvas.getMatrix().invert(mMapMatrix);
        }

        mPaint.setColor(unselectedColor);
        canvas.drawPath(centerPath, mPaint);
        canvas.drawPath(rightPath, mPaint);
        canvas.drawPath(bottomPath, mPaint);
        canvas.drawPath(leftPath, mPaint);
        canvas.drawPath(topPath, mPaint);

        if (!isSelected) return;
        mPaint.setColor(selectedColor);
        switch (mTouchArea) {
            case TouchArea.LEFT:
                canvas.drawPath(leftPath, mPaint);
                break;
            case TouchArea.TOP:
                canvas.drawPath(topPath, mPaint);
                break;
            case TouchArea.RIGHT:
                canvas.drawPath(rightPath, mPaint);
                break;
            case TouchArea.BOTTOM:
                canvas.drawPath(bottomPath, mPaint);
                break;
            case TouchArea.CENTER:
                canvas.drawPath(centerPath, mPaint);
                break;
        }
        Log.e("zhen", " touchArea: "   mTouchArea);

        //Android还提供了一个RegionIterator来对Region中的所有矩阵进行迭代,
        // 可以使用该类,获得某个Region的所有矩阵
        //通过遍历region中的矩阵,并绘制出来,来绘制region
//        mPaint.setColor(Color.RED);
//        RegionIterator iterator = new RegionIterator(topRegion);
//        Rect r = new Rect();
//        while (iterator.next(r)) {
//            canvas.drawRect(r, mPaint);
//        }
//
//        mPaint.setColor(Color.BLUE);
//        RegionIterator iterator1 = new RegionIterator(leftRegion);
//        Rect r1 = new Rect();
//        while (iterator1.next(r1)) {
//            canvas.drawRect(r1, mPaint);
//        }
//
//        mPaint.setColor(Color.BLACK);
//        RegionIterator iterator2 = new RegionIterator(rightRegion);
//        Rect r2 = new Rect();
//        while (iterator2.next(r2)) {
//            canvas.drawRect(r2, mPaint);
//        }
//
//        mPaint.setColor(Color.YELLOW);
//        RegionIterator iterator3 = new RegionIterator(bottomRegion);
//        Rect r3 = new Rect();
//        while (iterator3.next(r3)) {
//            canvas.drawRect(r3, mPaint);
//        }
//
//        mPaint.setColor(Color.GREEN);
//        RegionIterator iterator4 = new RegionIterator(centerRegion);
//        Rect r4 = new Rect();
//        while (iterator4.next(r4)) {
//            canvas.drawRect(r4, mPaint);
//        }
    }

    private MenuListener mListener;

    public void setListener(MenuListener listener) {
        mListener = listener;
    }

    // 点击事件监听器
    public interface MenuListener {
        void onMenuClicked(int type, boolean isSelected);
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持Devmax。

Android自定义View实现遥控器按钮的更多相关文章

  1. HTML5 input新增type属性color颜色拾取器的实例代码

    type 属性规定 input 元素的类型。本文较详细的给大家介绍了HTML5 input新增type属性color颜色拾取器的实例代码,感兴趣的朋友跟随脚本之家小编一起看看吧

  2. amazeui模态框弹出后立马消失并刷新页面

    这篇文章主要介绍了amazeui模态框弹出后立马消失并刷新页面,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. 移动HTML5前端框架—MUI的使用

    这篇文章主要介绍了移动HTML5前端框架—MUI的使用的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  4. html5 canvas合成海报所遇问题及解决方案总结

    这篇文章主要介绍了html5 canvas合成海报所遇问题及解决方案总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  5. Html5 video标签视频的最佳实践

    这篇文章主要介绍了Html5 video标签视频的最佳实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  6. HTML5在微信内置浏览器下右上角菜单的调整字体导致页面显示错乱的问题

    HTML5在微信内置浏览器下,在右上角菜单的调整字体导致页面显示错乱的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

  7. AmazeUI 模态窗口的实现代码

    这篇文章主要介绍了AmazeUI 模态窗口的实现代码,代码简单易懂,非常不错,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  8. ios – containerURLForSecurityApplicationGroupIdentifier:在iPhone和Watch模拟器上给出不同的结果

    我使用默认的XCode模板创建了一个WatchKit应用程序.我向iOSTarget,WatchkitAppTarget和WatchkitAppExtensionTarget添加了应用程序组权利.(这是应用程序组名称:group.com.lombax.fiveminutes)然后,我尝试使用iOSApp和WatchKitExtension访问共享文件夹URL:延期:iOS应用:但是,测试NSURL

  9. ios – UIPopoverController出现在错误的位置

    所以我花了一些时间寻找答案,但到目前为止还没有找到任何答案.我正在尝试从UIInputAccessoryView上的按钮呈现弹出窗口.UIBarButtonItem我想显示popover来自定制视图,所以我可以使用图像.我创建这样的按钮:当需要显示popover时,我这样做:但我得到的是:弹出窗口看起来很好,但它应该出现在第一个按钮上时出现在第二个按钮上.然后我发现了这个问题:UIBarButto

  10. ios – 关闭UIBarButtonItem上的突出显示

    我正在尝试使用UIBarButtonItem在我的UIToolbar上添加标题.我使用简单的风格,看起来很好,但我似乎无法让它停止突出显示触摸.“突出显示时触摸”选项不适用于条形按钮项目.有没有快速简便的方法来做到这一点?

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

  7. Android notifyDataSetChanged() 动态更新ListView案例详解

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部